Angular ViewChildren 没有立即从 ngFor 中看到所有 children
Angular ViewChildren does not see all children from ngFor immediately
我有一个奇怪的行为 @ViewChildren 对应于 ngFor 生成的 children 组件。 @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);
}
}
我们可以通过单击按钮添加 children 组件。
在 indexes 数组中添加一个元素后,在 ngFor 循环中生成所有 children - 我们没有刚刚添加的元素。
我可以理解这种行为 - 因为也许 child 组件需要一些时间来创建它,并且引擎决定在创建完整的 child 组件之前先查看控制台日志。
但是我在 child 组件中创建了发射器,表明 child 的视图和模型都已初始化。但是......在 parent 组件中处理这个事件 - 我们仍然不知何故没有这个项目。这怎么可能?
Child分量:
export class InternalComponent implements AfterViewInit {
@Input()
index;
@Output()
afterViewInit: EventEmitter<any> = new EventEmitter<any>();
ngAfterViewInit() {
this.afterViewInit.emit();
}
}
通知 QueryList
内容已更改的标准方法是在 ngAfterViewInit
中订阅其 changes
事件:
@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);
...
});
}
上面的事件处理可能就是您所需要的。如果你还想在InternalComponent
中实现afterViewInit
事件,你可以传递一个组件的引用作为事件的参数:
export class InternalComponent implements AfterViewInit {
@Output() afterViewInit = new EventEmitter<InternalComponent>();
ngAfterViewInit() {
this.afterViewInit.emit(this);
}
}
并在事件处理程序中检索组件:
(afterViewInit)="onAfterViewInit($event)"
onAfterViewInit(component: InternalComponent) {
this.useNewInternalComponent(component);
...
}
我有一个奇怪的行为 @ViewChildren 对应于 ngFor 生成的 children 组件。 @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);
}
}
我们可以通过单击按钮添加 children 组件。
在 indexes 数组中添加一个元素后,在 ngFor 循环中生成所有 children - 我们没有刚刚添加的元素。
我可以理解这种行为 - 因为也许 child 组件需要一些时间来创建它,并且引擎决定在创建完整的 child 组件之前先查看控制台日志。
但是我在 child 组件中创建了发射器,表明 child 的视图和模型都已初始化。但是......在 parent 组件中处理这个事件 - 我们仍然不知何故没有这个项目。这怎么可能?
Child分量:
export class InternalComponent implements AfterViewInit {
@Input()
index;
@Output()
afterViewInit: EventEmitter<any> = new EventEmitter<any>();
ngAfterViewInit() {
this.afterViewInit.emit();
}
}
通知 QueryList
内容已更改的标准方法是在 ngAfterViewInit
中订阅其 changes
事件:
@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);
...
});
}
上面的事件处理可能就是您所需要的。如果你还想在InternalComponent
中实现afterViewInit
事件,你可以传递一个组件的引用作为事件的参数:
export class InternalComponent implements AfterViewInit {
@Output() afterViewInit = new EventEmitter<InternalComponent>();
ngAfterViewInit() {
this.afterViewInit.emit(this);
}
}
并在事件处理程序中检索组件:
(afterViewInit)="onAfterViewInit($event)"
onAfterViewInit(component: InternalComponent) {
this.useNewInternalComponent(component);
...
}