Angular 4中获取mat-row的ViewContainerRef的最优方案
解决Mat-Table排序后行ViewContainerRef索引不匹配的问题
这个问题我之前也踩过坑!核心原因是ViewChildren返回的容器数组是按照组件初始化时的顺序排列的,而Mat-Table排序后会重新排列视图中的行(甚至会复用行元素),但ViewChildren的数组并不会同步更新顺序,导致你用当前视图的索引去取旧顺序的容器,自然会匹配到错误的行。
最直接的解决方法是跳过索引,在点击事件中直接获取当前行的ViewContainerRef,完全不需要依赖ViewChildren查询。具体步骤如下:
1. 修改模板,直接传递当前行的ViewContainerRef
把原来的点击事件参数改成直接传递当前行模板变量的ViewContainerRef:
<mat-row #myRow *matRowDef="let row; columns: colInfo;" (click)="expandRow(myRow.viewContainerRef, row)" ></mat-row>
2. 更新组件中的expandRow方法
不再通过索引去取容器,直接使用传入的ViewContainerRef来创建组件,同时可以增加重复点击的处理(比如清除已存在的组件):
import { ViewContainerRef, ComponentFactoryResolver } from '@angular/core'; import { DetailTableComponent } from './detail-table.component'; // ... 组件类其他代码 constructor(private resolver: ComponentFactoryResolver) {} expandRow(container: ViewContainerRef, rowData: any) { // 如果当前行已经有展开的组件,先清除 if (container.length > 0) { container.clear(); return; } // 创建并挂载子组件 const factory = this.resolver.resolveComponentFactory(DetailTableComponent); const componentRef = container.createComponent(factory); // 给子组件传递当前行的数据(如果需要) componentRef.instance.rowData = rowData; }
为什么这个方法有效?
- 每次点击行时,我们直接获取的是当前被点击行元素对应的
ViewContainerRef,完全不依赖索引或ViewChildren的数组顺序。 - 不管表格如何排序、过滤,只要点击的是目标行,就能拿到正确的容器,从根源上解决了索引不匹配的问题。
另外,如果你还是想保留ViewChildren的方式,也可以通过给Mat-Table设置trackBy函数来确保行数据和视图的对应关系,但这种方法不如直接传递容器直观可靠。
内容的提问来源于stack exchange,提问作者Gagan Jaura
相关产品推荐
相关产品推荐

