【问题标题】:Angular Lifecycle Hook - Constructor-initialised data loads after view initAngular Lifecycle Hook - 在视图初始化后加载构造函数初始化的数据
【发布时间】:2018-08-13 02:52:59
【问题描述】:

我已经加载了一个 firestore 文档,并在组件的构造函数中将其转换为一个普通的 js 对象,然后在模板中访问该对象的字段值,这意味着它们需要一秒钟的时间来加载。结果,即使 do 渲染到 DOM,我在浏览器控制台中收到以下类型的错误(访问 {{invoice.id}} 时出现以下错误:

无法读取未定义的属性“id”

据我了解,构造函数中定义的任何内容在初始化时都应该立即在视图中可用,那么为什么会发生这种情况/如何防止这种情况发生?

view-invoice.component.html:

<h4 class="page-title">Invoice Summary</h4>

<p>ID: {{ invoice.invoiceId }}</p>
<p>Reference: {{ invoice.reference }}</p>
<p>Date: {{ invoice.date | date: 'dd/MM/yyyy' }}</p>

view-invoice.component.ts:

import { Component, OnInit, AfterViewInit, Input } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { AngularFireDatabase } from 'angularfire2/database';
import { AngularFirestore, AngularFirestoreCollection, AngularFirestoreDocument } from 'angularfire2/firestore';
import { AuthService } from '../../services/auth.service';
import { InvoiceService } from '../invoice.service';
import { Invoice } from '../invoiceModel';
import 'rxjs/add/operator/mergeMap';

@Component({
  selector: 'app-view-invoice',
  templateUrl: './view-invoice.component.html',
  styleUrls: ['./view-invoice.component.scss']
})

export class ViewInvoiceComponent implements OnInit, AfterViewInit {    
  userId: string;

  invoiceId: any;
  //    invoice: Observable<Invoice>;
  invoice: any;

  constructor(private authService: AuthService, private invoiceService: InvoiceService, private db: AngularFirestore, private route: ActivatedRoute) {
    this.userId = this.authService.user.uid;

    this.route.params.subscribe(params => {
        this.invoiceId = params.id;
    })

  this.db.collection('/users').doc(this.userId).collection('/invoices')
  .doc(this.invoiceId).ref.get().then(snapshot => {
        const data = snapshot.data();
        this.invoice = data;
    })
  }

  ngOnInit() {
    this.getInvoice();
  }

  ngAfterViewInit() {       
  }
}

【问题讨论】:

  • 能出示相关代码sn-p吗?
  • 对不起,我跑题了
  • 您的数据是否可能是异步检索的,您需要使用异步管道?
  • 刚刚尝试使用这样的异步管道,但它应该是无效的:

    ID: {{ (invoice | async)?.invoiceId }}

  • 尝试移动 this.getInvoice();在 ngAfterViewInit 中。您的代码不起作用,因为您正在使用 subscribe 获取 invoiceId,这意味着您的下一个调用 (this.db.collection('/users')) 可能会在您获得 InvoiceId 之前执行。因此移动 getInvoice 和 this.db.collection('/users').doc(this.userId).collection('/invoices') .doc(this.invoiceId).ref.get().then(snapshot = > ....) 在 ngAfterViewInit 中并使用 InvoiceId 放置一个 if 条件,因此只有 this.db.collection('/users').... 在您获得发票 ID 后执行。

标签: angular typescript firebase google-cloud-firestore lifecycle


【解决方案1】:

负责获取发票数据的代码部分是异步的。因此,虽然在构造函数中调用该方法,但在呈现 HTML 模板时响应可能(并且几乎总是)不可用。有几种方法可以防止这种情况。其中之一是简单地将 HTML 标签包装在 ng-container 中,只有在数据可用后才会呈现:

<ng-container *ngIf="invoice">
  <p>ID: {{ invoice.invoiceId }}</p>
  <p>Reference: {{ invoice.reference }}</p>
  <p>Date: {{ invoice.date | date: 'dd/MM/yyyy' }}</p>
</ng-container>

【讨论】:

  • @nick.cook 这与我在上半部分的评论有何不同,因为我还写道,您的订阅功能可能不会在组件初始化时为您提供数据?
  • 因为你说的是​​代码中任何地方都不存在的函数的函数回调需要移动,我什至对你说这无关紧要,在函数被删除后留下删除。这对其他任何事情都没有影响
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-02
  • 2011-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多