* ng用于显示数据,但引发“未定义”错误

时间:2018-12-04 19:40:16

标签: angular typescript ngfor

我有一个* ngFor指令,该指令可以正常工作并在浏览器中显示数据。虽然我的Chrome控制台显示“未定义”错误。

http.service.ts:

getExerciseProgress(exId: number): Observable<Exercise> {
    return this.http.get<Exercise>(this.baseURL + 'exercises/GetProgressionByExerciseId/' + exId)
  }

view-exercise.component.ts:

 exercise: Exercise;

  constructor(private http: HttpService) { }


  ngOnInit() {
    this.http.getExerciseProgress(7).subscribe(ex =>{
      this.exercise = ex;
      console.log(this.exercise);
    });
  }

作为参数传递的7是出于测试目的,当我记录结果时,该对象似乎就是我要寻找的对象。带有嵌套Progress数组的Exercise对象。

view-exercise.component.html:

<p *ngFor="let p of exercise.progress">{{ p.bpm }}</p>

以上一行是在我的Chrome控制台窗口中引发以下消息的一行。 “错误TypeError:无法读取未定义的属性'progress'”。尽管如此,我的浏览器仍显示正确的信息。

客户端模型(以防万一其相关):

export class Exercise {

id: number;
description: string;
progress: Progress[];

constructor(id: number, description: string, progress: Progress[]){
    this.id = id;
    this.description = description;
    this.progress = progress;
}

export class Progress {

id: number;
dateAttempted: Date;
bpm: number;

constructor(id: number, dateAttempted: Date, bpm: number){
    this.id = id;
    this.dateAttempted = dateAttempted;
    this.bpm = bpm;
}

}

预先感谢

3 个答案:

答案 0 :(得分:2)

这是一个竞争条件:模板首次加载时,this.exercise仍为undefined。然后,一旦Observable解析并分配了值,就会触发change detection cycle,运行*ngFor,您会看到这些值。

有两种典型的模式可以解决此问题:

使用elvis operator(这可能是您最好的选择,因为您只有一个访问者):

<p *ngFor="let p of exercise?.progress">{{ p.bpm }}</p>

?.的意思是“如果定义了左侧的操作数,则访问该运算符右侧的属性”。这样写,很显然可以将它们链接起来:exercise?.progress?.timer?.started

或者在容器元素上使用防护,当您有许多访问器并且不想在各处重复?.时,这种方法会更好:

<ng-container *ngIf="exercise">
  <p *ngFor="let p of exercise.progress">{{ p.bpm }}</p>
<ng-container>

在上面的示例中,我使用了<ng-container />,因为它没有呈现到DOM中,但是您可以像在<div />这样的真实元素上轻松使用它。这通常在*ngIf="exercise; else no-data"模式中使用,其中#no-data是另一个ng-template,可在加载数据时替换div。


仅供参考,由于Angular使用polyfills,因此您可以在TypeScript中安全地使用template strings。意思是你可以写

this.baseURL + 'exercises/GetProgressionByExerciseId/' + exId

`${this.baseURL}/exercises/GetProgressionByExerciseId/${exId}`

有些人觉得更容易阅读。

答案 1 :(得分:0)

您可以尝试以下方法: <p *ngFor="let p of exercise?.progress">{{ p.bpm }}</p>

我的猜测是,即使您的数据不是init的,也要首先尝试显示一些内容。

答案 2 :(得分:0)

您的DOM似乎在服务调用结束并且您有可用数据之前正在练习中寻找进度对象。

您应该在可用时循环遍历它,这意味着API调用已完成并且您有数据:

<p *ngFor="let p of exercise?.progress">{{ p.bpm }}</p>

或使用*ngIf来实现。