【问题标题】:How to update dependency injection token value如何更新依赖注入令牌值
【发布时间】:2018-03-27 02:02:17
【问题描述】:

Angular 依赖注入允许您使用令牌而不是服务类来注入字符串、函数或对象。

我在我的模块中这样声明它:

providers: [{ provide: MyValueToken, useValue: 'my title value'}]

我是这样使用它的:

constructor(@Inject(MyValueToken) my_value: string) {
  this.title = my_value;
}

但是,我怎样才能从组件中更新值并让其他组件每次获取新值?换句话说,我想模拟使用 BehaviorSubject 之类的东西来发出和接收值的功能。

如果这是不可能的,那么如果这些注入令牌值只提供静态数据,那么它们有什么用,因为我可以简单地在我的组件中声明静态值并直接使用它。

【问题讨论】:

  • 是的,你可以声明那个静态值,如果它只用在一个地方你应该。当在多个地方使用 DI 并且您想要一致性以及想要注入替代值进行测试时,DI 非常有用。如果两者都不是,不要增加复杂性——仅仅因为你可以,并不意味着你应该这样做。我建议阅读angular.io/guide/dependency-injection-in-action
  • @jonsharpe 答案很好!谢谢你:)

标签: angular typescript angular-services angular-decorator angular-di


【解决方案1】:

关于为什么...

由于您还想知道为什么要注入静态结构,Angular Material 经常这样做以向组件提供配置。

例如。对于Chips control

@NgModule({
  providers: [
    {
      provide: MAT_CHIPS_DEFAULT_OPTIONS,
      useValue: {
        separatorKeyCodes: [ENTER, COMMA]
      }
    }
  ]
})

无需了解这些数据代表什么,只需意识到您正在注入一个令牌MAT_CHIPS_DEFAULT_OPTIONS,其值为{ separatorKeyCodes: [ENTER, COMMA] }

这将从您的 AppModule 或您定义的任何模块或组件继承 - 就像任何其他可注入服务一样。这同样可以在您的 @Component@Directive 定义中为单个组件(及其子组件)提供配置。

当然,当您的应用程序中的不同模块或组件需要不同的配置时,您可以将其注入其中,并且只有子组件会继承它。

说实话,这样做似乎很痛苦,而不仅仅是在组件上设置一个值,但这就是它适用于许多 Angular Material 控件的方式。当然,好处是你只做一次,一切都会继承它。

【讨论】:

    【解决方案2】:

    如果您不想使用 BehaviorSubject,您可以提供一个带有 getter 和 setter 的简单类。

    class MyValue {
    
      get value(): string {
        return this._value;   
      }
    
      set value(val: string) {
       this._value = val;
      }
      private _value = '';
    
    }
    
    const MY_VALUE_TOKEN = new InjectionToken<MyValue>('MY_VALUE_TOKEN ');
    
    // Provide class in either module or component providers array.
    providers: [
      { provide: MY_VALUE_TOKEN , useClass: MyValue },
    ]
    
    class MyComponent {
    
      // Inject in component constructor
      constructor(
        @Inject(MY_VALUE_TOKEN) private _myValue: MyValue,
      ) {
    
        // Access current value
        console.log(this._myValue.value);
    
        // Set new value
        this._myValue.value = 'new value';
      }
    
    }
    
    

    【讨论】:

    • 这不会只更新注入变量的“本地”副本吗?我相信 OP 正在询问如何在全球范围内应用更改
    • @SajjanSarkar 这实际上是模块或组件级别的全局变量。你可以在两个地方注入它,它们可以“互相交谈”。除非您将其添加到每个组件的提供者中,否则它不会每次都是本地副本。
    • 但是就目前而言,它并不是很有用,因为没有考虑更改检测 - 您的更新值可能不会立即显示(取决于进行更改的原因)。这就是为什么 observable 选项可能有意义的原因,因为您可以处理更改,但不要忘记取消订阅或使用异步管道。如果您能够在组件上设置 Input value 属性,则更可取
    • @Simon_Weaver 我完全同意。如果您需要对变化做出反应,使用 observable 绝对是更好的方法。
    【解决方案3】:

    除了向导:

    如果您有一个用例,其中每个消费者都需要自己的 BehaviourSubject 实例。 (我恰好在这个用例中)。确保你定义了一个工厂。

    const myFactory = () => { return new BehaviorSubject<string>('') };
    
    providers: [
        { provide: MyValueToken, useFactory: myFactory }
    ]
    
    // Then, as proposed in the top-answer.
    
    // consumer
    constructor(@Inject(MyValueToken) my_value: BehaviorSubject) {
      my_value.subscribe((my_value)=>this.title = my_value);
    }
    
    // producer
    constructor(@Inject(MyValueToken) my_value: BehaviorSubject) {
      my_value.next('my title value');
    }

    【讨论】:

    • 这样可以确保每个消费者都有自己的 BehaviourSubject,对吗?否则,在生产者中发出新值也会触发所有其他消费者的更新。
    • 每个具有共同祖先的组件或模块“提供”这个令牌将共享它的同一个实例。如果您将 { provide: MyValueToken, useFactory: myFactory } 放在两个组件上,它们将无法“相互交谈”,但如果您将其声明在一个共同的祖先组件或模块上,那么它们就可以。
    【解决方案4】:

    您可以使用BehaviorSubject,而不是不可变的原语,然后在一个组件中访问和更新它并在另一个组件中订阅:

    providers: [{ provide: MyValueToken, useValue: new BehaviorSubject('')}]
    
    // consumer
    constructor(@Inject(MyValueToken) my_value: BehaviorSubject) {
      my_value.subscribe((my_value)=>this.title = my_value);
    }
    
    // producer
    constructor(@Inject(MyValueToken) my_value: BehaviorSubject) {
      my_value.next('my title value');
    }
    

    【讨论】:

    • @HamedBaatour DI 模式有益的原因相同。可扩展性和可测试性。
    • @HamedBaatour,见this
    • @HamedBaatour 这总是取决于。如果有多个组件依赖于此值,则应在组件之外明确定义该值。如果它是静态的,它可以是一个常数。如果它发生变化,它应该包含在一个服务中,就像这个例子一样。
    • @HamedBaatour 是的。但是,如果多个组件使用的值没有机会更改,您可以安全地跳过 DI 部分并将其设置为const。同样,它总是取决于。 window 永远不会改变,但出于测试原因将其保留为提供者是有意义的,例如 that
    • @estus 非常感谢您澄清所有这些。竖起大拇指!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-28
    • 2014-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多