如何在Angular循环内动态注入对应组件?
Angular循环中为每个项动态注入对应组件的实现方法
我们可以通过ViewContainerRef.createComponent()动态注入Angular组件,其中ViewContainerRef指向<ng-template #ref>这类模板引用。但如果模板引用是在@for循环中创建的(如下代码所示),该如何为每个循环项注入对应的组件?
用户提供的模板代码:
@for(item of items; track item){ <div> <!-- some nested markups --> <!-- inject each item's component here --> <!-- this should be created several times, once for each item --> <ng-template #ref></ng-template> </div> }
组件类中的数据:
items = [ Component1, Component2 ];
实现步骤
获取循环中的所有模板引用
由于循环会生成多个<ng-template #ref>,不能用@ViewChild获取单个实例,要使用@ViewChildren来获取所有对应的ViewContainerRef集合,类型为QueryList<ViewContainerRef>。在视图初始化后动态创建组件
在ngAfterViewInit钩子中(确保视图已渲染完成),遍历QueryList和items数组,为每个ViewContainerRef创建对应的组件。如果items会动态变化,还要订阅QueryList的changes事件,同步更新组件。清理组件避免内存泄漏
当组件销毁或者items变化时,要销毁之前创建的动态组件,防止内存泄漏。
完整代码示例
组件类代码
import { Component, ViewChildren, QueryList, ViewContainerRef, AfterViewInit, OnDestroy } from '@angular/core'; import { Component1 } from './component1.component'; import { Component2 } from './component2.component'; @Component({ selector: 'app-dynamic-components', templateUrl: './dynamic-components.component.html' }) export class DynamicComponentsComponent implements AfterViewInit, OnDestroy { items = [Component1, Component2]; @ViewChildren('ref') viewContainers!: QueryList<ViewContainerRef>; // 存储创建的组件实例,用于后续清理 private componentRefs: any[] = []; ngAfterViewInit(): void { this.renderComponents(); // 监听视图容器变化,比如循环项增删时重新渲染 this.viewContainers.changes.subscribe(() => { this.clearComponents(); this.renderComponents(); }); } private renderComponents(): void { this.viewContainers.forEach((vcr, index) => { const ComponentClass = this.items[index]; if (ComponentClass) { const componentRef = vcr.createComponent(ComponentClass); this.componentRefs.push(componentRef); // 如果需要给组件传值,可以在这里设置 // componentRef.instance.someProperty = this.items[index].data; } }); } private clearComponents(): void { this.componentRefs.forEach(ref => ref.destroy()); this.componentRefs = []; } ngOnDestroy(): void { this.clearComponents(); } }
模板代码(与用户提供的一致)
@for(item of items; track item){ <div> <!-- some nested markups --> <!-- inject each item's component here --> <!-- this should be created several times, once for each item --> <ng-template #ref></ng-template> </div> }
注意事项
- 确保动态组件(
Component1、Component2)已在当前模块的declarations数组中声明(Angular 14+ 无需再添加到entryComponents)。 @for循环的track item要保证每个item有唯一标识,避免不必要的视图销毁重建。- 如果
items是异步加载的,要在数据加载完成后再调用renderComponents()方法。
内容的提问来源于stack exchange,提问作者Sherif eldeeb
相关产品推荐
相关产品推荐

