Угловой 7: данные отображаются на странице, но консоль имеет свойство «Не удается прочитать» - PullRequest
0 голосов
/ 02 апреля 2019

Я работаю с приложением Angular 7, которое создаю, и у меня возникли проблемы с возвратом данных из моего API и правильной записью их на странице.

Я пытался следовать инструкциямобещания и наблюдаемые, но я, похоже, не смог ни заставить данные правильно отображаться в заголовке, ни в этом случае заставить консоль перестать выдавать ошибки.Я попытался использовать оператор 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 возвращает)

Но в консоли я вижу следующие ошибки (Ссылка содержит изображение ошибок консоли, но это специфика: Невозможно прочитать свойство 'имя' изundefined

Я понимаю, что выдает ошибку до того, как API предоставит данные для рендеринга, но я не уверен, как обойти это, поскольку изменил HTML на {{this.data?.name}}делает панель навигации пустой, а {{this.data.name?}} вызывает эту ошибку: Неожиданный конец выражения: {{this.data.name?}}

Ответы [ 3 ]

1 голос
/ 02 апреля 2019

удалить "это" в файле HTML

{{ data.name }}
0 голосов
/ 02 апреля 2019

Решением этой проблемы было использование углового ядра 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
}
0 голосов
/ 02 апреля 2019

В вашем случае 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 pipe, чтобы заключить Angular с самой подпиской.

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

и в шаблоне

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