Angular ViewChildren不会立即从ngFor中看到所有子项

时间:2018-08-07 14:33:16

标签: angular ngfor viewchild

与ngFor生成的子组件相对应的@ViewChildren行为很奇怪。 @ViewChildren查询在很长一段时间内看不到元素在数组中站立。我所有的代码都在Plunker中-在打开控制台的情况下查看。

这是我的主要组成部分:

@Component({
    selector: 'my-app',
    template: `
        <button (click)="addInternalComponent()">Add internal component</button>
        <app-internal #internals *ngFor="let i of indexes" [index]="i
(afterViewInit)="onAfterViewInit()"></app-internal>
    `,
})
export class App {
    @ViewChildren('internals') internals: QueryList<InternalComponent>;
    indexes = [];
    addInternalComponent() {
        console.log('adding internal component!');
        this.indexes.push(this.indexes.length);
        console.log('Not complete list', this.internals._results);

    }

    onAfterViewInit() {
        console.log('onAfterViewInit - still not complete list', this.internals._results);
    }
}

可以通过单击按钮添加哪些子组件。

在将元素添加到可在ngFor循环中生成所有子代的索引数组中之后-我们没有刚刚添加的那个子代。

我可以理解这种行为-因为子组件可能需要一些时间来创建它,并且引擎决定在创建完整子组件之前控制台日志。

但是,我在子组件中创建了发射器,表示子视图和模型均已初始化。但是...在父组件中处理此事件-我们仍然不知何故没有此项。这怎么可能?

子组件:

export class InternalComponent implements AfterViewInit {
  @Input()
  index;
  @Output()
  afterViewInit: EventEmitter<any> = new EventEmitter<any>();

  ngAfterViewInit() {
    this.afterViewInit.emit();
  }

}

1 个答案:

答案 0 :(得分:2)

通知QueryList的内容已更改为订阅changesngAfterViewInit事件的标准方法:

@ViewChildren("internals") internals: QueryList<InternalComponent>;

ngAfterViewInit() {
  this.internals.changes.subscribe((list: QueryList<InternalComponent>) => {
    // The updated QueryList is available here (with list or with this.internals)
    this.doSomethingWithInternals(list);
    this.doSomethingWithNewInternal(list.last);
    ...
  });
}

上面的事件处理可能就是您所需要的。如果您仍想在afterViewInit中实现InternalComponent事件,则可以将对组件的引用作为事件的参数传递:

export class InternalComponent implements AfterViewInit {
  @Output() afterViewInit = new EventEmitter<InternalComponent>();

  ngAfterViewInit() {
    this.afterViewInit.emit(this);
  }

}

并在事件处理程序中检索组件:

(afterViewInit)="onAfterViewInit($event)"

onAfterViewInit(component: InternalComponent) {
    this.useNewInternalComponent(component);
    ...
}