【问题标题】:Change detection on injected service's property in angular2angular2中注入服务属性的变化检测
【发布时间】:2016-07-28 01:04:25
【问题描述】:

Angular1老手在这里,尝试学习angular2。我有一个带有状态服务的组件(下面的MyState),它被注入到自身及其子组件中。我想观察服务状态的变化,然后更新顶级组件中的另一个成员,如下:

import { Component, Input } from '@angular/core';

class Item {
  constructor(public name: string) {}
}

class MyState {
  selectedItems: Item[] = [];
  addItem(item: Item) {
    this.selectedItems.push(item);
  }
}

// subcomponent
@Component({
  selector: '[item]',
  template: `
    <!-- state changed from subcomponent: -->
    <button (click)="state.addItem(model)">
      select item {{model.name}}
    </button>
  `
})
class ItemComponent {
  @Input() model: Item;
  constructor(private state: MyState){}
}

// main component
@Component({
  selector: 'items',
  template: `
    <h1> Available Items: </h1>
    <ul>
      <li *ngFor="let item of items" item [model]="item"></li>
    </ul>
    <h1> Added Items: </h1>
    <p>{{ addedItemsString }}</p>
  `,
  providers: [MyState],
  directives: [ItemComponent]
})
class ListComponent {
  @Input() items: Item[];
  private addedItemsString: string = '';

  constructor(private state: MyState) {
    // listen for changes to this.state.selectedItems to   
    // call this.updateAddedItemsString
  }

  updateAddedItemsString () {
    this.addItemsString = this.state.selectedItems.map(i => i.name).join(', ');
  }
}

我的问题是:我应该如何在 ListComponent 构造函数中实现伪代码?

当然,addItemsString 成员是人为设计的,当然可以在模板本身中完成,但为了我的问题,假设 updateAddedItemsString 可以做很多更复杂的事情,更新 ListComponent 的单独成员.

提前致谢!

【问题讨论】:

标签: typescript angular angular2-services angular2-changedetection


【解决方案1】:

在您的服务中使用BehaviorSubject&lt;Item[]&gt;,并让您的 ListComponent 订阅对该可观察数组的更改:

class MyState {
  private _selectedItems: Item[] = [];
  private _selectedItemsSource = new BehaviorSubject<Item[]>(this._selectedItems);
  selectedItems$ = this._selectedItemsSource.asObservable();
  addItem(item: Item) {
    this._selectedItems.push(item);
    this._selectedItemsSource.next(this._selectedItems);
  }
}

@Component({
  selector: 'items',
  template: `<h1> Available Items: </h1>
    <ul>
      <li *ngFor="let item of items" item [model]="item"></li>
    </ul>
    <h1> Added Items: </h1>
    <div>{{ addedItemsString }}</div>`,
  providers: [MyState],
  directives: [ItemComponent]
})
class ListComponent {
  @Input() items: Item[];
  private addedItemsString: string = '';
  constructor(private state: MyState) {}
  ngOnInit() {
    this.subscription = this.state.selectedItems$.subscribe(
      items => this.addedItemsString = items.map(i => i.name).join(', '));
  }
  ngOnDestroy() {
    // prevent memory leak when component is destroyed
    this.subscription.unsubscribe();
  }
}

Plunker

每次调用next() 时,我都会发出整个数组。这确保了以后订阅 BehaviorSubject 的任何其他组件都将获得完整列表。如果您没有这个要求,您可以在调用 addItem() 时仅发出新值。

【讨论】:

  • 感谢@markrajcok 的回答。这似乎适用于 Subject 以及 BehaviorSubject。有什么区别?
  • 请参阅我在答案中提供的the BehaviorSubject link。总之,BehaviorSubject 具有“当前值”的概念,因此每当新的观察者订阅时,它将立即收到“当前值”。一个主题不会那样做。如果您使用 Subject 并发出一个值,然后再订阅,新的 Observer 将不会看到先前发出的值——它只会获得未来发出的值。由于您似乎在共享当前状态(而不仅仅是新值),我建议使用 BehaviorSubject。
  • 感谢您,并为没有先关注该链接而道歉。帮了我很多忙!
猜你喜欢
  • 1970-01-01
  • 2019-06-09
  • 1970-01-01
  • 1970-01-01
  • 2017-06-03
  • 2016-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多