Angular Lifecycle Hook - 视图初始化后构造函数初始化的数据加载
Angular Lifecycle Hook - Constructor-initialised data loads after view init
我已经加载了一个 firestore 文档并在组件的构造函数中将其转换为普通的 js 对象,然后在模板中访问了该对象的字段值,这意味着它们需要一秒钟的时间来加载。结果,即使渲染到 DOM,我在浏览器控制台中收到以下类型的错误(此处在访问 {{invoice.id}}:
Cannot read property 'id' of undefined
根据我的理解,构造函数中定义的任何内容在初始化时都应该立即在视图中可用,所以为什么会这样occurring/how 我可以阻止这种情况吗?
查看-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>
查看-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() {
}
}
负责获取发票数据的代码部分是异步的。因此,虽然在构造函数中调用了该方法,但在呈现 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>
我已经加载了一个 firestore 文档并在组件的构造函数中将其转换为普通的 js 对象,然后在模板中访问了该对象的字段值,这意味着它们需要一秒钟的时间来加载。结果,即使渲染到 DOM,我在浏览器控制台中收到以下类型的错误(此处在访问 {{invoice.id}}:
Cannot read property 'id' of undefined
根据我的理解,构造函数中定义的任何内容在初始化时都应该立即在视图中可用,所以为什么会这样occurring/how 我可以阻止这种情况吗?
查看-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>
查看-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() {
}
}
负责获取发票数据的代码部分是异步的。因此,虽然在构造函数中调用了该方法,但在呈现 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>