简体   繁体   English

Observable 只更新一次 UI

[英]Observable updates UI only once

I am fairly new to Angular (10) and try to grasp the concept of Observables.我对 Angular(10)相当陌生,并试图掌握 Observables 的概念。 I have a Service and a Component, the services fills an array with participants and the component is supposed to display them我有一个服务和一个组件,这些服务用参与者填充了一个数组,组件应该显示它们

Service服务

export class MercureService {

  private _participants = new BehaviorSubject<ParticipantDTO[]>([]);
  private participantList: Array<ParticipantDTO> = [];

  constructor() {
  }

  get participants$(): Observable<Array<ParticipantDTO>> {
    return this._participants.asObservable();
  }

  admin_topic(topic: AdminTopic): void {

    const url = new URL(environment.mercure);
    url.searchParams.append('topic', `${topic.sessionUuid}_${topic.userUuid}`);

    const eventSource = new EventSource(url.toString());
    eventSource.onmessage = event => {
      const json = JSON.parse(event.data);
      console.log('NEW EVENT');
      // ...
      if (json.event === BackendEvents.NEW_PARTICIPANT) {
        this.participantList.push({voter: json.data.voter, voterUuid: json.data.voterUuid, vote: '0'});
        this._participants.next(this.participantList);
      }
    };
  }

Component.ts组件.ts

export class StartSessionComponent implements OnInit, OnDestroy {
  // ...
  unsubscribe$: Subject<void> = new Subject<void>();
  participantList: ParticipantDTO[];

  constructor(
    // ...
    public mercure: MercureService
  ) {}

  ngOnInit(): void {
    this.mercure.participants$
      .pipe(takeUntil(this.unsubscribe$))
      .subscribe((data) => {
        this.participantList = data;
      });

    this.mercure.admin_topic({sessionUuid: '123', userUuid: '456'});
  }

  ngOnDestroy(): void {
    this.unsubscribe$.next();
    this.unsubscribe$.complete();
  }

Component.html组件.html

...
  <div *ngFor="let participant of this.mercure.participants$ | async">
    <p>{{participant.voter}} - Vote ({{participant.vote}})</p>
  </div>
...

So I am no sending a message and it gets picked up by the EventSource, the console says所以我没有发送消息,它被 EventSource 接收, console

NEW EVENT

and the UI gets updated (adds a new <p>WHATEVER NAME - VOTE XXX</p> ).并且 UI 得到更新(添加一个新的<p>WHATEVER NAME - VOTE XXX</p> )。 However, when I send a second message from the Server, I get但是,当我从服务器发送第二条消息时,我得到

NEW EVENT

again, but the UI does not get updated.再次,但用户界面没有更新。 I suspect I am doing sth wrong with the Observable, can somebaody help please?我怀疑我在 Observable 上做错了什么,有人可以帮忙吗?

这是一个预期的行为,因为this.participantList引用了一个已经被主题存储的值(因为引用没有改变),你可能想要传播你的数组以在每次你想要更新它的时候创建一个新数组价值:

this._participants.next(....this.participantList);

The issue is that EventSource events are emitted outside of Angular, so that whatever happens inside your eventSource.onmessage is not updating the UI properly.问题是 EventSource 事件是在 Angular 之外发出的,因此无论在eventSource.onmessage内部发生什么,都不会正确更新 UI。 That's why you need to wrap whatever is happening inside the onmessage to be run inside the Angular with the help of NgZone.这就是为什么你需要在 NgZone 的帮助下将onmessage发生的任何事情包装起来,以便在 Angular 中运行。

See example:见示例:

  constructor(
    private zone: NgZone
  ) { }

  admin_topic(topic: AdminTopic): void {
    const url = new URL(environment.mercure);
    url.searchParams.append('topic', `${topic.sessionUuid}_${topic.userUuid}`);

    const eventSource = new EventSource(url.toString());
    eventSource.onmessage = event => {
      this.zone.run(() => { // This is what you need
        const json = JSON.parse(event.data);
        console.log('NEW EVENT');
        // ...
        if (json.event === BackendEvents.NEW_PARTICIPANT) {
          this.participantList.push({ voter: json.data.voter, voterUuid: json.data.voterUuid, vote: '0' });
          this._participants.next(this.participantList);
        }
      })
    };
  }

Another solution would be to use Event Source wrapper that will do the exact same thing for you and will give you the ease of use.另一种解决方案是使用 Event Source 包装器,它可以为您做完全相同的事情,并为您提供易用性。 It will be also wrapped in the Observable, so that you can have rich experience.它也会被包裹在 Observable 中,让你拥有丰富的经验。 See this article for example: Event Source wrapped with NgZone and Observable例如,参见这篇文章: 事件源用 NgZone 和 Observable 包装

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

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