Angular 2如何点击按钮后在指定<tr>后插入模板?
你的方法是不正确的,核心问题有两个:
TemplateRef是Angular封装的模板引用对象,它本身并没有elementRef.nativeElement这个可直接访问的原生DOM节点——你试图获取的这个属性根本不存在,自然拿不到有效内容;- 直接用原生DOM方法插入模板,绕开了Angular的变更检测和组件生命周期管理,很容易导致视图与数据不同步,这完全不符合Angular的设计理念。
下面给你两种符合Angular 2风格的解决方案,按需选择:
方案一:用状态数组控制模板显示(简单直观,推荐)
思路是给每个元素维护一个“是否显示模板”的状态,点击按钮时切换对应索引的状态,再通过*ngIf控制模板的显示位置。
首先在组件类里新增一个状态数组:
elements = [/* 这里放你的元素数据 */]; // 用数组对应每个行的模板显示状态,初始都为false showTemplateStatus: boolean[] = []; showTemplate(i: number) { // 切换对应索引的状态,实现点击显示/隐藏 this.showTemplateStatus[i] = !this.showTemplateStatus[i]; }
然后修改模板,把模板和对应行绑定在一起(用<ng-container>避免生成多余DOM节点):
<tbody> <ng-container *ngFor="let el of elements; let i = index"> <tr> <td> <button (click)="showTemplate(i)">Click me {{i}}</button> </td> </tr> <!-- 只有对应状态为true时,才渲染模板 --> <tr *ngIf="showTemplateStatus[i]"> <td>You have clicked a button</td> </tr> </ng-container> </tbody>
方案二:用ViewContainerRef动态插入模板(灵活可控)
如果你的场景需要更动态的模板操作(比如模板要绑定当前行的数据,或者不想提前渲染所有模板),可以用Angular的ViewContainerRef来实现:
先修改模板,给每个行后面加一个<ng-container>作为模板的插入容器:
<tbody> <tr *ngFor="let el of elements; let i = index"> <td> <button (click)="showTemplate(i)">Click me {{i}}</button> </td> </tr> <!-- 每个行对应一个容器,用来动态插入模板 --> <ng-container *ngFor="let el of elements; let i = index" #templateContainer></ng-container> </tbody> <!-- 定义要插入的模板 --> <template #myTemplate> <tr> <td>You have clicked a button</td> </tr> </template>
然后在组件类里通过ViewChildren获取所有容器,再动态插入模板:
import { Component, ViewChild, ViewChildren, TemplateRef, ViewContainerRef, QueryList } from '@angular/core'; @Component({ // 你的组件元数据(selector、templateUrl等) }) export class YourComponent { elements = [/* 你的元素数据 */]; @ViewChild('myTemplate') myTemplate: TemplateRef<any>; // 获取所有模板容器的引用 @ViewChildren('templateContainer') templateContainers: QueryList<ViewContainerRef>; showTemplate(i: number) { const targetContainer = this.templateContainers.toArray()[i]; if (targetContainer.length) { // 如果容器里已经有模板,就清空 targetContainer.clear(); } else { // 将模板插入到对应索引的容器中 targetContainer.createEmbeddedView(this.myTemplate); } } }
这个方案完全遵循Angular的生命周期和变更检测机制,不会出现视图不同步的问题。
总结一下:如果只是简单的显示/隐藏需求,优先用方案一;如果需要更复杂的动态模板操作,再考虑方案二。绝对不要用原生DOM方法去操作Angular模板,这会埋下很多难以排查的隐患。
内容的提问来源于stack exchange,提问作者AngularDebutant
相关产品推荐
相关产品推荐

