Подтвердить что ты не робот

Обновление изменений переменных компонентов из службы с помощью angular2

В моем приложении есть служба NameService, которая содержит имя.

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

import {Component, Injectable} from 'angular2/core'

// Name Service

@Injectable()
class NameService {
  name: any;
  constructor() {
    this.name = "Jack";
  }
  change(){
    this.name = "Jane";
  }
}

// The navbar
@Component({
  selector: 'navbar',
  template: '<div>This is the navbar, user name is {{name}}.</div>'
})
export class Navbar {
  name: any;
  constructor(nameService: NameService) {
    this.name = nameService.name;
  }
}

// The content area
@Component({
  selector: 'thecontent',
  template: '<div>This is the content area. Hello user {{name}}. <button (click)=changeMyName()>Change the name</button></div>'
})
export class TheContent {

  name: any;

  constructor(public nameService: NameService) {
    this.name = nameService.name;
  }
  changeMyName() {
       this.nameService.change();
     console.log(this.nameService.name);
  }
}


@Component({
  selector: 'app',
  providers: [NameService],
  directives: [TheContent, Navbar],
  template: '<navbar></navbar><thecontent></thecontent>'
})
export class App {
  constructor(public nameService: NameService) {
  }
}
4b9b3361

Ответ 1

Предоставить событие в службе и подписаться на него в компонентах:

@Injectable()
class NameService {
  name: any;
  // EventEmitter should not be used this way - only for `@Output()`s
  //nameChange: EventEmitter<string> = new EventEmitter<string>();
  nameChange: Subject<string> = new Subject<string>();
  constructor() {
    this.name = "Jack";
  }
  change(){
    this.name = 'Jane';
    this.nameChange.next(this.name);
  }
}
export class SomeComponent { 
  constructor(private nameService: NameService) {
    this.name = nameService.name;
    this._subscription = nameService.nameChange.subscribe((value) => { 
      this.name = value; 
    });
  }

  ngOnDestroy() {
   //prevent memory leak when component destroyed
    this._subscription.unsubscribe();
  }
}

См. также
angular.io - COMPONENT INTERACTION - Родитель и дети обмениваются данными через службу

Ответ 2

Так как name в NameService является примитивным типом, вы получите другой экземпляр в службе и ваших компонентах. Когда вы меняете name в NameService, свойства компонента по-прежнему имеют начальное значение, и привязка не работает должным образом.

Здесь вы должны применить угловое "правило точки" и привязать к ссылочному типу. Измените NameService, чтобы сохранить объект, содержащий имя.

export interface Info {
   name:string;
}

@Injectable()
class NameService {
  info: Info = { name : "Jack" };
  change(){
    this.info.name = "Jane";
  }
}

Вы можете привязываться к этому объекту и автоматически получать обновления для свойства name.

// The navbar
@Component({
  selector: 'navbar',
  template: '<div>This is the navbar, user name is {{info.name}}.</div>'
})
export class Navbar {
  info: Info;
  constructor(nameService: NameService) {
    this.info = nameService.info;
  }
}

Ответ 3

Я думаю, что решение, предоставленное Günter, является лучшим.

Тем не менее, вы должны знать, что службы Angular2 являются одноточечными, которые имеют место в дереве инжекторов. Это означает, что:

  • если вы определяете свою службу на уровне приложения (во втором параметре метода bootstrap), экземпляр может быть общим для всех элементов (компонентов и службы).
  • если вы определяете свою службу на уровне компонента (в атрибуте providers), экземпляр будет специфичен для компонента и его вспомогательных компонентов.

Подробнее о таком аспекте вы можете прочитать в документе "Иерархическая зависимость": https://angular.io/docs/ts/latest/guide/hierarchical-dependency-injection.html

Надеюсь, это поможет вам, Thierry