当模板中有ngIf时如何识别Angular2组件是不是已完全加载(包括ViewChilds)

Posted

技术标签:

【中文标题】当模板中有ngIf时如何识别Angular2组件是不是已完全加载(包括ViewChilds)【英文标题】:How to Identify whether a Angular2 component is completely loaded ( including ViewChilds ) when there is ngIf in template当模板中有ngIf时如何识别Angular2组件是否已完全加载(包括ViewChilds) 【发布时间】:2016-11-14 13:00:56 【问题描述】:

当模板中有条件加载子组件的 ngIf 时,是否可以识别 Angular2 组件(此处为 AppComponent)是否已完全加载(包括 ViewChilds )。

参考:Angular 2 @ViewChild annotation returns undefined 此示例取自上述参考资料。感谢kenecaswell

import Component, ViewChild, OnInit, AfterViewInit from 'angular2/core';
import ControlsComponent from './child-component-1';
import SlideshowComponent from './slideshow/slideshow.component';

@Component(
    selector: 'app',
    template:  `
        <div *ngIf="controlsOn">
            <controls ></controls>
            <slideshow></slideshow>
        </div>
    `,
    directives: [SlideshowComponent, ControlsComponent]
)

export class AppComponent 
    @ViewChild(ControlsComponent) controls:ControlsComponent;   
    @ViewChild(SlideshowComponent) slide:SlideshowComponent;

    controlsOn:boolean = false;

    ngOnInit() 
        console.log('on init', this.controls);
        // this returns undefined
    

    ngAfterViewInit() 
        console.log('on after view init', this.controls);
        // this returns null
    


由于 ngIf 条件,在加载子组件之前触发 ngOnInit && ngAfterViewInit

我需要确定 SlideshowComponent 和 ControlsComponent 何时加载并基于此执行操作。

我有一个 hacky 解决方案,当有多个 ViewChilds 时不适合(它们是不同类型的) - 使用事件发射器通知孩子何时加载。

我发布这个问题是因为经过数小时的研究没有合适的解决方案。

【问题讨论】:

【参考方案1】:

您可以将内容包装在 *ngIf 中,这样 html 在 ngOnInit 完成之前不会显示任何内容。

<div *ngIf="loaded">
    /* all codes go here */
<div>

OnInit()
    foo();
    bar(()=>
        this.loaded = true;
    );

【讨论】:

【参考方案2】:

PLUNKER

尝试使用ViewChildren 代替ViewChild,它提供了一个changes Observable,我们可以将其用作挂钩。

要跟踪所有 ViewChildren,您可以将他们的 changes Observables 合并为一个并订阅它,然后您将获得单点操作,就像这样

  @ViewChildren(ChildCmp) children: QueryList<ChildCmp>;
  @ViewChildren(AnotherChildCmp) anotherChildren: QueryList<ChildCmp>;

  childrenDetector: Observable<any>; // merged observable to detect changes in both queries

  ngAfterViewInit()
    this.childrenDetector = Observable.merge(this.children.changes, this.anotherChildren.changes)

    this.childrenDetector.subscribe(() => 

      // here you can even check the count of view children, that you queried
      // eg:  if(this.children.length === 1 && this.anotherChildren.length === 1)  bothInitialized(); 
      // or something like that

      alert('you just initialized a children');
    );
  

【讨论】:

嗨,我的问题是我有 3 个不同类型的组件 (ViewChild),我想确定何时加载所有三个组件 (ViewChild) 并执行操作。我已经更新了这个问题。谢谢 好的,这个问题是由*ngIf 不让子组件在ViewInit 上初始化引起的,现在ViewChildren 更有意义,因为它可以告诉您子组件何时初始化,参见this PLUNKER 好的,我现在正在尝试,可观察到的更改是否会通知所有更改(角度文档不完整)。 是的,当查询到的组件数量变化时触发 我认为根据github.com/angular/angular/issues/9689,ViewChildren、ContentChildren 更改流在 2.0.0 中已损坏

以上是关于当模板中有ngIf时如何识别Angular2组件是不是已完全加载(包括ViewChilds)的主要内容,如果未能解决你的问题,请参考以下文章

如何检查ngIf是不是生效

Angular 2+ - 当 ngIf 导致隐藏时将 ngModel 设置为 null

Angular 2 将组件动态附加到 DOM 或模板

Angular 2 - 组件内的 formControlName

如何检查 Observable 数组的长度

Angular 2 路由器:添加 RouteParam 而不重新创建组件