Angular 4:组件在运行时无法访问数据属性
Angular 4: data attribute not accessible to component at runtime
我正在使用 Angular 4、AngularFire2 和 Firebase 构建应用程序。
我 运行 遇到了问题。
在我的 app-component.html 我有这个:
<app-person *ngIf="isPerson" [personId]="personId" [treeUniqueName]="treeUniqueName" [treeId]="treeId"></app-person>
在我的 app-component.ts 我有这个:
import { Component } from '@angular/core';
import { AngularFireDatabase } from 'angularfire2/database';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
isTree = false;
treeId;
treeUniqueName = '';
treeDisplayName = '';
isPerson = false;
personId = '';
isLocation = false;
locationId = '';
isEvent = false;
eventId = '';
isDocument = false;
documentId = '';
isSitemap = false;
data = '';
headers = new Headers();
constructor(
protected db: AngularFireDatabase
) {}
ngOnInit() {
let cleanPath = location.pathname.toLowerCase().replace(/\/+$/, '');
//console.info(cleanPath);
cleanPath = cleanPath || '';
if (cleanPath === '/sitemap') {
this.isSitemap = true;
}
let routeSegments = cleanPath.split("/");
//console.info(routeSegments);
if (routeSegments.length >= 3 && routeSegments[1] == 'family')
{
this.treeUniqueName = routeSegments[2].toLowerCase();
let output = this.db.list('/tree', {
query: {
orderByChild: 'unique',
equalTo: this.treeUniqueName
}
}).subscribe(tree => {
this.treeId = tree[0].$key;
this.treeDisplayName = tree[0].display;
console.log(this.treeId);
})
if (routeSegments.length == 3)
{
this.isTree = true;
}
else if (routeSegments.length == 5 && routeSegments[3].toLowerCase() == 'person')
{
this.isPerson = true;
this.personId = routeSegments[4].toLowerCase();
}
else if (routeSegments.length == 5 && routeSegments[3].toLowerCase() == 'location')
{
this.isLocation = true;
this.locationId = routeSegments[4].toLowerCase();
}
else if (routeSegments.length == 5 && routeSegments[3].toLowerCase() == 'event')
{
this.isEvent = true;
this.eventId = routeSegments[4].toLowerCase();
}
else if (routeSegments.length == 5 && routeSegments[3].toLowerCase() == 'document')
{
this.isDocument = true;
this.documentId = routeSegments[4].toLowerCase();
}
}
}
}
如果我检查该页面,我发现数据属性已正确绑定:
<app-person ng-reflect-tree-id="964f000f-573b-481b-9e43-18bc77" ng-reflect-tree-unique-name="doe" ng-reflect-person-id="b051cb21-6419-4b6f-85b5-d0891bc2a166"><!--bindings={
"ng-reflect-ng-for-of": ""
}--></app-person>
但是在我的 人中。component.ts 我有这个:
import { Component, Input, OnInit, OnDestroy } from '@angular/core';
import { AngularFireDatabase } from 'angularfire2/database';
import { Title, Meta } from '@angular/platform-browser';
import { EventPipe } from './event.pipe';
@Component({
selector: 'app-person',
templateUrl: './person.component.html'
})
export class PersonComponent implements OnInit, OnDestroy {
@Input() treeId: string;
@Input() treeUniqueName: string;
@Input() personId: string;
subscriptions: Array<any> = new Array<any>();
people: Array<any> = new Array<any>();
constructor(
private title: Title,
private meta: Meta,
protected db: AngularFireDatabase
){}
ngOnInit() {
console.log(this.treeId); // FOR SOME REASON THIS IS EMPTY
this.subscriptions.push(
this.db.list('/person', {
query: {
queryByChild: 'tree',
equalTo: this.treeId,
limitToLast: 200
}
}).subscribe(people => {
this.people = people;
})
);
}
ngOnDestroy() {
this.subscriptions.forEach(s => s.unsubscribe());
}
}
出于某种原因 this.treeId 始终为空。
我猜这与页面生命周期有关?如果是这样,我该如何解决?
正确的语法是:
<app-person *ngIf="isPerson" [personId]="personId" [treeUniqueName]="treeUniqueName" [treeId]="treeId"></app-person>
@Input 值不需要 {{}}。
对于isPerson,需要在父组件中设置,而不是通过@Input在子组件中设置。
由于您的 treeId 仅在异步函数的回调中定义(在您的情况下......订阅结果),除非您告诉它,否则子组件不会等待它。它会在应用程序组件执行后立即实例化。您有一个布尔值用于告诉子组件等待 'isPerson',但似乎有许多条件会将 'isPerson' 设置为 true,无论 treeId 是否仍然是空字符串。所有这些条件都在订阅部分之后同步评估,它们也不会等待。您可以尝试不将 treeId 初始化为空字符串,只需声明它并将其保留为未定义。
treeId: string;
然后将应用组件模板中的 ngIf 语句更改为
*ngIf="isPerson && treeId"
Vega 是对的,您通常会避免在模板的构造函数中放置任何东西,但在您的情况下 none 这些东西似乎取决于视图或任何输入,所以您可能没问题.我认为这与您的问题无关,但是您如何在没有位置提供程序的情况下在您的应用程序组件中获得 'location'?
我找到了解决这个问题的方法。我将代码从 app.component.ts
的构造函数中移出并移到了 ngOnInit 中。这没有效果。
然后我将 'person.component.ts' 的 ngOnInit 切换为 ngOnChanges。现在这段代码在 app.component.ts
代码之后触发——这是我们想要的。
this.treeId
现在已正确填充。
我正在使用 Angular 4、AngularFire2 和 Firebase 构建应用程序。
我 运行 遇到了问题。
在我的 app-component.html 我有这个:
<app-person *ngIf="isPerson" [personId]="personId" [treeUniqueName]="treeUniqueName" [treeId]="treeId"></app-person>
在我的 app-component.ts 我有这个:
import { Component } from '@angular/core';
import { AngularFireDatabase } from 'angularfire2/database';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
isTree = false;
treeId;
treeUniqueName = '';
treeDisplayName = '';
isPerson = false;
personId = '';
isLocation = false;
locationId = '';
isEvent = false;
eventId = '';
isDocument = false;
documentId = '';
isSitemap = false;
data = '';
headers = new Headers();
constructor(
protected db: AngularFireDatabase
) {}
ngOnInit() {
let cleanPath = location.pathname.toLowerCase().replace(/\/+$/, '');
//console.info(cleanPath);
cleanPath = cleanPath || '';
if (cleanPath === '/sitemap') {
this.isSitemap = true;
}
let routeSegments = cleanPath.split("/");
//console.info(routeSegments);
if (routeSegments.length >= 3 && routeSegments[1] == 'family')
{
this.treeUniqueName = routeSegments[2].toLowerCase();
let output = this.db.list('/tree', {
query: {
orderByChild: 'unique',
equalTo: this.treeUniqueName
}
}).subscribe(tree => {
this.treeId = tree[0].$key;
this.treeDisplayName = tree[0].display;
console.log(this.treeId);
})
if (routeSegments.length == 3)
{
this.isTree = true;
}
else if (routeSegments.length == 5 && routeSegments[3].toLowerCase() == 'person')
{
this.isPerson = true;
this.personId = routeSegments[4].toLowerCase();
}
else if (routeSegments.length == 5 && routeSegments[3].toLowerCase() == 'location')
{
this.isLocation = true;
this.locationId = routeSegments[4].toLowerCase();
}
else if (routeSegments.length == 5 && routeSegments[3].toLowerCase() == 'event')
{
this.isEvent = true;
this.eventId = routeSegments[4].toLowerCase();
}
else if (routeSegments.length == 5 && routeSegments[3].toLowerCase() == 'document')
{
this.isDocument = true;
this.documentId = routeSegments[4].toLowerCase();
}
}
}
}
如果我检查该页面,我发现数据属性已正确绑定:
<app-person ng-reflect-tree-id="964f000f-573b-481b-9e43-18bc77" ng-reflect-tree-unique-name="doe" ng-reflect-person-id="b051cb21-6419-4b6f-85b5-d0891bc2a166"><!--bindings={
"ng-reflect-ng-for-of": ""
}--></app-person>
但是在我的 人中。component.ts 我有这个:
import { Component, Input, OnInit, OnDestroy } from '@angular/core';
import { AngularFireDatabase } from 'angularfire2/database';
import { Title, Meta } from '@angular/platform-browser';
import { EventPipe } from './event.pipe';
@Component({
selector: 'app-person',
templateUrl: './person.component.html'
})
export class PersonComponent implements OnInit, OnDestroy {
@Input() treeId: string;
@Input() treeUniqueName: string;
@Input() personId: string;
subscriptions: Array<any> = new Array<any>();
people: Array<any> = new Array<any>();
constructor(
private title: Title,
private meta: Meta,
protected db: AngularFireDatabase
){}
ngOnInit() {
console.log(this.treeId); // FOR SOME REASON THIS IS EMPTY
this.subscriptions.push(
this.db.list('/person', {
query: {
queryByChild: 'tree',
equalTo: this.treeId,
limitToLast: 200
}
}).subscribe(people => {
this.people = people;
})
);
}
ngOnDestroy() {
this.subscriptions.forEach(s => s.unsubscribe());
}
}
出于某种原因 this.treeId 始终为空。
我猜这与页面生命周期有关?如果是这样,我该如何解决?
正确的语法是:
<app-person *ngIf="isPerson" [personId]="personId" [treeUniqueName]="treeUniqueName" [treeId]="treeId"></app-person>
@Input 值不需要 {{}}。
对于isPerson,需要在父组件中设置,而不是通过@Input在子组件中设置。
由于您的 treeId 仅在异步函数的回调中定义(在您的情况下......订阅结果),除非您告诉它,否则子组件不会等待它。它会在应用程序组件执行后立即实例化。您有一个布尔值用于告诉子组件等待 'isPerson',但似乎有许多条件会将 'isPerson' 设置为 true,无论 treeId 是否仍然是空字符串。所有这些条件都在订阅部分之后同步评估,它们也不会等待。您可以尝试不将 treeId 初始化为空字符串,只需声明它并将其保留为未定义。
treeId: string;
然后将应用组件模板中的 ngIf 语句更改为
*ngIf="isPerson && treeId"
Vega 是对的,您通常会避免在模板的构造函数中放置任何东西,但在您的情况下 none 这些东西似乎取决于视图或任何输入,所以您可能没问题.我认为这与您的问题无关,但是您如何在没有位置提供程序的情况下在您的应用程序组件中获得 'location'?
我找到了解决这个问题的方法。我将代码从 app.component.ts
的构造函数中移出并移到了 ngOnInit 中。这没有效果。
然后我将 'person.component.ts' 的 ngOnInit 切换为 ngOnChanges。现在这段代码在 app.component.ts
代码之后触发——这是我们想要的。
this.treeId
现在已正确填充。