简体   繁体   English

使异步管道更新Angular 2中的视图

[英]Make the async pipe update the view in Angular 2

The component seen below would display a list of events in the template upon initialization ( ngOnInit() ). 初始化后,下面看到的组件将在模板中显示事件列表( ngOnInit() )。 However, when the addEvent() is invoked, the view will not be updated. 但是,当调用addEvent() ,该视图将不会更新。 Why is this the case? 为什么会这样呢?

How can I make the view to be updated whenever I publish new data to a data store that's used to populate the observable property ( events: Observable<Event[]> )? 每当我将新数据发布到用于填充observable属性( events: Observable<Event[]> )的数据存储中时,如何使视图更新?

@Component({
    template:
        <ul>
            <li *ngFor="let event of events | async"
{{ event.title }}
</li>
</ul>
<button (click)="addEvent()">Add event</button>

})
export class EventCenterListComponent implements OnInit {
    events: Observable<Event[]>;

    constructor(
        private eventsService: EventsService,
    ) {}


    ngOnInit() {
        this.events = return this.eventsService.getEvents();
    }

    addEvent() {
        this.eventsService.createEvent('New event'); <--this would add one event to the data source
        this.events = this.eventsService.getEvents(); <-- that reassignment would not be seen in the template
    }
}

I've seen that many tutorials, including Angulat's official tutorial convert the Observable into a plain array and then push new values into the array, eg: 我已经看到很多教程,包括Angulat的官方教程,都将Observable转换为纯数组,然后push新值push入数组,例如:

heroes: Hero[];

addHero(name: string) {
  this.heroService.create(name)
                   .subscribe(
                     hero  => this.heroes.push(hero), <-- that would work 
                     error =>  this.errorMessage = <any>error);
} 

But is the above really necessary? 但是以上真的必要吗? Cannot I operate directly on observables and have the view updated? 我不能直接对可观察对象进行操作并更新视图吗?

Yeah, better not to subscribe in the component. 是的,最好不要订阅该组件。

Here's one idea. 这是一个主意。 The events service keeps a private array of events, and fires a subject every time it changes. 事件服务保留事件的私有数组,并在每次更改主题时触发它。 The component can use the async pipe so that its view is updated whenever that subject fires. 该组件可以使用异步管道,以便在触发该主题时更新其视图。

@Injectable()
export class EventsService {
  private events: Event[] = [];

  private eventsSubject = new Subject<Event[]>();
  private _events$ = this.eventsSubject.asObservable();

  createEvent(title: string) {
    const newEvent: Event = {title};
    this.events = [...this.events, newEvent];
    this.eventsSubject.next(this.events);
  }

  getEvents$() {
    return this._events$;
  }
}

@Component({
  template: `
    <ul>
      <li *ngFor="let event of events | async">{{ event.title }}</li>
    </ul>
    <button (click)="addEvent()">Add event</button>`
})
export class EventCenterListComponent {
  events: Observable<Event[]>;

  constructor(private eventsService: EventsService) {
    this.events = eventsService.getEvents$();
  }

  addEvent() {
    this.eventsService.createEvent('New event');
  }
}

UPDATE 更新

New idea from a closer reading of your question. 通过仔细阅读您的问题获得新思路。 Assuming EventService works like this: 假设EventService的工作方式如下:

createEvent(title: string): Observable<void> // post one new event to server
getEvents(): Observable<Event[]> // get list of events from server

...And you simply want to refetch the list of the events after posting a new one, then implement EventCenterListComponent like this: ...并且您只是想在发布新事件后重新获取事件列表,然后实现如下的EventCenterListComponent:

export class EventCenterListComponent {
  events: Observable<Event[]>;

  private newEventSubject = new Subject<string>();

  constructor(eventsService: EventsService) {
    const eventWasCreated$ = this.newEventSubject.mergeMap(title =>
      eventsService.createEvent(title));

    const shouldRefresh$ = eventWasCreated$.startWith(undefined);

    this.events = shouldRefresh$.switchMap(() =>
      eventsService.getEvents());

    // optional, if you are going to subscribe to `events` in more
    // than one place:
    this.events = this.events.share();
  }

  addEvent() {
    this.newEventSubject.next('New event');
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM