Angular 7:数据显示在页面上,但控制台具有“无法读取”属性

时间:2019-04-02 14:50:37

标签: angular promise observable angular7

我正在使用自己正在构建的Angular 7应用程序,但是在从API返回数据并将其正确写入页面时遇到一些问题。

我尝试遵循有关Promise和Observable的指南,但是我似乎无法使数据正确显示在标题中,或者在这种情况下,无法使控制台停止抛出错误。我尝试使用Elvis运算符,但这只是使显示值空白而不是显示值。

resume.service.ts

export class ResumeService {
  nameURL: string = 'REDACTED';

  constructor(private http: HttpClient) { }

  getName() {
    return this.http.get(this.nameURL);
  }
}

返回this.http.get(this.nameURL);

[
  {
    name: 'My Name'
  }
]

navbar.component.ts

export class NavbarComponent implements OnInit {
  data: Name;
  reason = '';
  @ViewChild('sidenav') sidenav: MatSidenav;

  constructor(private http: HttpClient, private resumeAPI: ResumeService) {
    this.resumeAPI.getName().subscribe(res => {
      this.data = res[0];
    });
  }

  close(reason: string) {
    this.reason = reason;
    this.sidenav.close();
  }
}

export interface Name {
  name: string
}

navbar.component.html

<div>
  <a routerLink="/">
    {{ this.data.name }}
  </a>
</div>

因此,在导航栏中,我看到this(它显示了我的名字,模糊区域是该区域-API返回的数据)

但是,在控制台中,我看到以下errors (该链接包含控制台错误的图片,但这是细节: 无法读取未定义的属性“名称”

我知道在API提供渲染数据之前它会引发错误,但是我不确定如何解决它,因为将HTML更改为{{this.data?.name}}会使导航栏成为空白,{{this.data.name? }}导致此错误:表达式的意外结尾:{{this.data.name? }}

3 个答案:

答案 0 :(得分:1)

删除HTML文件中的“ this”

{{ data.name }}

答案 1 :(得分:0)

在您的情况下,this.http.get()执行异步操作。因此,在运行this.data = res[0];行之前,this.data尚未初始化,并且会引发错误。

您只需要检查this.data是否通过

设置
<a routerLink="/" *ngIf="this.data">
    {{ this.data.name }}
</a>

<a routerLink="/">
    {{ this.data?.name }}
</a>

但是我认为第一个更有意义,因为您可能不希望在设置链接文本之前显示链接


OR

您可以使用async管道使Angular处理订阅本身。

this.data = this.resumeAPI.getName().pipe(map(res => res[0]));

在模板中

<a routerLink="/">
   {{ (this.data | async).name }}
</a>

答案 2 :(得分:0)

此问题的解决方案是将Angular核心ChangeDetectorRef与detectChanges()一起使用。所有功劳归于 @MullisS

在TypeScript文件中,我们进行了更改: import { Component, ViewChild } from '@angular/core';import { Component, ViewChild, ChangeDetectorRef } from '@angular/core';(添加了ChangeDetectorRef)。

在构造函数中,我们进行了更改: constructor(private resumeAPI: ResumeService) {constructor(private ref: ChangeDetectorRef, private resumeAPI: ResumeService) {

然后,在订阅功能中,我们进行了更改:

this.resumeAPI.getName().subscribe(res => {
  this.data = res[0];
});

this.resumeAPI.getName().subscribe(res => {
  this.data = res[0];
  this.ref.detectChanges();
});

下面是完整的代码解决方案,以供参考: navbar.component.html

<a routerLink="/" >
  {{ this.data?.name }}
</a>

navbar.component.html

import { Component, ViewChild, ChangeDetectorRef } from '@angular/core';
import { MatSidenav } from '@angular/material/sidenav';
import { HttpClient } from '@angular/common/http';
import { ResumeService } from '../services/resume.service';

@Component({
  selector: 'app-navbar',
  templateUrl: './navbar.component.html',
  styleUrls: ['./navbar.component.scss'],
  providers: [ResumeService]
})
export class NavbarComponent {
  data: Name;
  reason = '';
  @ViewChild('sidenav') sidenav: MatSidenav;

  constructor(private ref: ChangeDetectorRef, private resumeAPI: ResumeService) {
    this.resumeAPI.getName().subscribe(res => {
      this.data = res[0];
      this.ref.detectChanges();
    });
  }

  close(reason: string) {
    this.reason = reason;
    this.sidenav.close();
  }
}

export interface Name {
  name: string
}