Как обновить значение токена внедрения зависимости

Внедрение угловых зависимостей позволяет вам вводить строку, функцию или объект, используя токен вместо класса обслуживания.

Я объявляю это в моем модуле так:

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

и я использую это так:

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

Однако как я могу обновить значение из компонента и позволить другим компонентам каждый раз получать новое значение? другими словами, я хочу имитировать функциональность использования чего-то вроде BehaviorSubject излучать и получать значения.

Если это невозможно, тогда какой смысл использовать значения этих токенов, если они предоставляют только статические данные, поскольку вместо этого я могу просто объявить статическое значение в моем компоненте и использовать его напрямую.

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');
}

In addition to the Wizard:

If you have a use-case where every consumer needs its own instance of BehaviourSubject. (I happen to be in this use-case). Make sure you define a factory.

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');
}

Если вы не хотите использовать BehaviorSubject, вы можете вместо этого предоставить простой класс с геттером и сеттером.

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';
  }

}

Относительно ПОЧЕМУ ...

Если вам интересно, ПОЧЕМУ вы можете захотеть внедрить статическую структуру, Angular Material делает это довольно часто, чтобы предоставить конфигурацию компонентам.

например. для контроля чипов :

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

Не нужно понимать, что представляют собой эти данные, просто поймите, что вы вводите токен MAT_CHIPS_DEFAULT_OPTIONS со значением { separatorKeyCodes: [ENTER, COMMA] }

Он будет унаследован от вашего AppModule или от того модуля или компонента, который вы его определите, как и любой другой вводимый сервис. Это также может быть в вашем @Component или же @Directive определение, чтобы предоставить конфигурацию только для одного компонента (и его дочерних элементов).

Конечно, когда другому модулю или компоненту в вашем приложении требуется другая конфигурация, вы вводите ее туда, и только дочерние компоненты наследуют ее.

Честно говоря, это может показаться сложной задачей вместо того, чтобы просто устанавливать значение для компонента, но именно так это работает для многих элементов управления Angular Material. И, конечно же, преимущество в том, что вы делаете это только один раз, и все это наследует.

Другие вопросы по тегам