首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >ngFor不显示来自可观察事件源的数据

ngFor不显示来自可观察事件源的数据
EN

Stack Overflow用户
提问于 2018-10-05 05:09:09
回答 4查看 662关注 0票数 3

在我的Angular6应用程序中,我遇到了一个使用async ngfor显示数据的问题。我期待一些服务器发送的事件从后端(只是对象与答案字符串字段)。当console.log显示来自服务的答案列表包含答案时,ngfor则什么也不显示。

下面是我的组件:

代码语言:javascript
运行
复制
import { Component } from '@angular/core';
import { Answer } from './answer';
import { AnswerReactiveService } from './answer-reactive.service';
import { Observable } from 'rxjs';

@Component({
  selector: 'app-answers',
  templateUrl: './answers.component.html',
  providers: [AnswerReactiveService],
  styleUrls: ['./answers.component.css']
})
export class AnswersComponent {
  answers: Observable<Answer[]>;

  constructor(private answerReactiveService: AnswerReactiveService) {
  }

  requestAnswerStream(): void {
    this.answers = this.answerReactiveService.getAnswerStream();
  }

}

以下是该服务:

代码语言:javascript
运行
复制
import { Injectable } from '@angular/core';

import { Answer } from './answer';

import { Observable } from 'rxjs';

@Injectable()
export class AnswerReactiveService {

  private answers: Answer[] = [];
  private url: string = 'http://localhost:8080/events/1';

  getAnswerStream(): Observable<Array<Answer>> {
    return Observable.create((observer) => {
      let url = this.url;
      let eventSource = new EventSource(url);
      eventSource.onmessage = (event) => {
        console.log('Received event: ', event);
        const json = JSON.parse(event.data);
        console.log(json);
        this.answers.push(new Answer(json['answer']));
        console.log(this.answers);
        observer.next(this.answers);
      };
      eventSource.onerror = (error) => {
        if (eventSource.readyState === 0) {
          console.log('The stream has been closed by the server.');
          eventSource.close();
          observer.complete();
        } else {
          observer.error('EventSource error: ' + error);
        }
      };
    });
  }
}

和HTML:

代码语言:javascript
运行
复制
<div class="row">
  <div class="col-md-8">
    <p>
      <button (click)="requestAnswerStream()">Gimmie answers</button>
    </p>
    <ul>
      <li *ngFor="let answer of answers | async">{{answer.answer}}</li>
    </ul>
  </div>
</div>
EN

回答 4

Stack Overflow用户

发布于 2018-10-06 00:50:29

经过研究,我用ngZone实现了这个结果。我在这里发现了类似的问题:https://blog.octo.com/en/angular-2-sse-and-changes-detection/

现在,我的服务代码看起来就像这样,它可以正常工作:

代码语言:javascript
运行
复制
      eventSource.onmessage = (event) => {
        this.zone.run(() => {
          console.log('Received event: ', event);
          const json = JSON.parse(event.data);
          this.answers.push(new Answer(json['answer']));
          observer.next(this.answers);
        });
      }; 

我只是想知道这个解决方案是否可以被认为是完全反应的?我找不到任何其他的方法来让它工作。

票数 2
EN

Stack Overflow用户

发布于 2018-10-05 06:02:50

这是一个同步性问题。Observable.create同步运行并创建一个可观察对象。来自您的EventSource的回调确实被调用了,但是已经太晚了,无法实现创建的observable。

解决方案是使用Subject,它是服务类的成员,它将一直存在,直到EventSource回调能够影响它。您必须将服务对象‘挂钩’到组件的构造函数中可见的组件。然后,getAnswerStream()变成triggerAnswerStream(),它将Eventsource发布事件设置为主题。

如下所示:

代码语言:javascript
运行
复制
@Component({
  selector: 'app-answers',
  templateUrl: './answers.component.html',
  providers: [AnswerReactiveService],
  styleUrls: ['./answers.component.css']
})
export class AnswersComponent {
  answers: Observable<Answer[]>;

  constructor(private answerReactiveService: AnswerReactiveService) {
    this.answers = answerReactiveService.answerStreamSubject.asObservable();
  }

  requestAnswerStream(): void {
    this.answerReactiveService.getAnswerStream();
  }

}

代码语言:javascript
运行
复制
@Injectable()
export class AnswerReactiveService {

  private answers: Answer[] = [];
  private url: string = 'http://localhost:8080/events/1';

  public answerStreamSubject: Subject<Array<Answer>>;

  triggerAnswerStream(): void {
      let url = this.url;
      let eventSource = new EventSource(url);
      eventSource.onmessage = (event) => {
        console.log('Received event: ', event);
        const json = JSON.parse(event.data);
        console.log(json);
        this.answers.push(new Answer(json['answer']));
        console.log(this.answers);
        this.answerStreamSubject.next(this.answers);
      };
      eventSource.onerror = (error) => {
        if (eventSource.readyState === 0) {
          console.log('The stream has been closed by the server.');
          eventSource.close();
          this.answerStreamSubject.complete();
        } else {
          this.answerStreamSubject.error('EventSource error: ' + error);
        }
      };
  }
}
票数 0
EN

Stack Overflow用户

发布于 2018-10-05 12:42:22

获得服务结果后,在使用observer.next()发出值之后,使用observer.complete完成序列

代码语言:javascript
运行
复制
eventSource.onmessage = (event) => {
        console.log('Received event: ', event);
        const json = JSON.parse(event.data);
        console.log(json);
        this.answers.push(new Answer(json['answer']));
        console.log(this.answers);
        observer.next(this.answers);
        observer.complete();
      };
   };

内部组件

代码语言:javascript
运行
复制
export class AnswersComponent implements OnInit {
  answers: Observable<Answer[]>;

  constructor(private answerReactiveService: AnswerReactiveService) {
  }

  ngOnInit(): void {
        this.answerReactiveService.getAnswerStream().subscribe((response)=>{
        this.answers=response;
    });
  }
}

然后在HTML语言中,您可以简单地迭代answers

代码语言:javascript
运行
复制
 <li *ngFor="let answer of answers">{{answer.answer}}</li>
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52655177

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档