Angular 4:运行时组件无法访问的数据属性

时间:2017-08-25 15:34:34

标签: angular typescript angularfire2

我正在使用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>

但是在我的 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始终为空。

我猜这与页面生命周期有关?如果是这样,我该如何解决它?

enter image description here

3 个答案:

答案 0 :(得分:0)

正确的语法是:

<app-person *ngIf="isPerson" [personId]="personId" [treeUniqueName]="treeUniqueName" [treeId]="treeId"></app-person>

对于@Input值,您不需要{{}}。

对于isPerson,您需要在父组件中设置它,而不是通过@Input在子组件中设置它。

答案 1 :(得分:0)

由于您的treeId仅在异步函数的回调中定义(在您的情况下...订阅结果),子组件除非您告诉它,否则不会等待它。它将在app组件发生后立即实例化。你有一个布尔值来告诉子组件等待“isPerson”,但似乎有许多条件会设置“isPerson”#39;为true,无论treeId是否仍为空字符串。所有这些条件都在订阅部分后同步评估,他们也不会等待。您可以尝试不将treeId初始化为空字符串,只需声明它并保持未定义。

 treeId: string;

然后将应用程序组件模板中的ngIf语句更改为

 *ngIf="isPerson && treeId"

Vega是正确的,你通常会避免在模板的构造函数中放置任何东西,但在你的情况下,这些东西似乎都不依赖于视图或任何输入,所以你可能很好。这是我认为与你的问题无关的事情,但是你如何得到&#39; location&#39;在没有位置提供商的应用程序组件中?

答案 2 :(得分:0)

我想出了解决这个问题的方法。我将代码移出app.component.ts的构造函数并进入ngOnInit。这没有效果。

然后我切换了'person.component.ts&#39;的ngOnInit。是一个ngOnChanges。现在,此代码在app.component.ts代码之后触发 - 这是所需的。

this.treeId现已正确填充。