http.get太慢,更改检测没有注册更改

时间:2017-06-28 12:16:59

标签: angular angular-http

我正在构建一个日历应用程序,它使用http.get从后端获取某一天的信息(当前后端是服务器模拟)。我的问题是,异步http.get的速度不足以在页面呈现期间传递数据,并且一旦数据到达,数据就不会显示,我相信更改检测应该正常选择。 关于http.get方法,我遵循Angular.io上的示例,在此处找到https://angular.io/guide/http#subscribe

代码:

FetchService:

getDayInfo(date: string): Observable<any> {
  return this.http.get(url)
    .map(this.extractData)
    .catch(this.handleError);
}

private extractData(res: Response) {
  let body = res.json();
  return body; // not really doing much with the data here yet
}

component.ts:

dayData: any[];
dayInfo: any[];

constructor(private fetcher: FetchService) {}

ngOnInit(): void {
  this.getDay();
  setTimeout(() => { this.setDayData(); }, 10); 
  // the setTimeout is mostly here for testing, tried to sort of set the
  // Data after the async http.get was done
}  

getDay () {
  this.fetcher.getDayInfo(this.date).subscribe(
    body => this.dayInfo = body,
  );
}

setDayData() {
  if (this.dayInfo) {
    this.dayData = this.dayInfo;
    console.log(this.dayData);
    // and some more things that only matter for some CSS markup
  }
}

component.html:

<!--{{ dayInfo[0].type.name }}-->
<div *ngIf="dayData">
  <div *ngFor="let data of dayData">
    <p>{{ data.type.name }}</p>
  </div>
</div>
<div *ngIf="!dayData">
  <p>Loading</p>
</div>

每天总是只显示加载,在超时后,控制台填充实际和正确的dayData,网站仍然只显示正在加载。 如果我在html中的{{dayInfo [0] .type.name}}中发表评论,我首先会在&#34; Loading&#34;并且一个错误说明dayInfo的控制台是未定义的,然后一点一点,填充日期,显示加载和我想要的数据,尽管控制台充满了上述错误。

现在,由于我无法加速异步http.get,有没有办法触发更改检测以获取dayData中的更改?或者任何其他解决方法让我显示正确的数据?

PS:在setDayData中控制日志记录dayData时我注意到的另一件事是有时日志没有列出所有日期,这意味着它可能显示一个月的前27天,但是没有关于日期的日志条目休息。不确定是什么原因引起的。

编辑: 在第一个评论和第一个答案之后,我将component.ts中的getDay方法更改为:

getDay () {
  this.fetcher.getDayInfo(this.date).subscribe(
    body => {
      this.dayInfo = body;
      this.setDayData();
  );
}

现在我在&#34; PS中描述了奇怪的行为:&#34;上面已经消失,所有日子都在日志中显示,尽管它们混在一起(不再按时间顺序排列)。 网站仍然只显示&#34;正在加载&#34;虽然并且没有更新到正确的数据。我可能需要在这里手动触发变化检测。

2 个答案:

答案 0 :(得分:3)

您的超时可能会在您获取数据之前触发。您可能希望从getDayInfo订阅块的主体中​​调用它,而不是从ngOnInit调用setDayData。

这将确保您获得数据,并在收到数据后调用您的后续方法。

ngOnInit(): void {
  this.getDay();
}  

getDay () {
  this.fetcher.getDayInfo(this.date).subscribe(
    body => {
        this.dayInfo = body;
        this.setDatData();
    }
  );
}

关于获取未定义的另一个问题 - 这是因为在首次显示模板时你有一个空数组(在运行setDayData方法之前它没有设置)。如果您真的想在屏幕上显示,也可以将其包装在ngIf中。这样你知道你也有数据。

答案 1 :(得分:1)

而不是使用Timeout,最好在回调中调用this.setData(),就像William指出的那样。这是因为我们实际上并不知道异步请求需要多长时间。

ngOnInit(): void {
  this.getDay();
}  

getDay () {
  this.fetcher.getDayInfo(this.date).subscribe(
    body => {
        this.dayInfo = body;
        this.setDatData(); // here
    }
  );
}

此后,由于某种原因,未运行更改检测,因此我们需要手动触发它。这可以通过ChangeDetectorRef实现,我们从@angular/core导入,将其注入构造函数:

constructor(private ref: ChangeDetectorRef) { }

然后在setDayData()

中调用它
setDayData() {
  if (this.dayInfo) {
    this.dayData = this.dayInfo;
    console.log(this.dayData);
    this.ref.detectChanges(); // here!
  }
}