最近在工作中使用angular,组件库使用ng-zorro-antd,边学边用。在写表格组件的时候发现,点击新增、删除就,数据改变,表格却没有更新。
代码如下:
<a (click)="addRow(item)">新增一列</a>
<nz-table
#basicTable
class="form-table"
[nzBordered]="true"
[nzData]="fields"
[nzShowPagination]="false">
<thead>
<tr>
<th>值的编号</th>
<th>字段</th>
<th>操作</th>
</tr>
</thead>
<tbody cdkDropList (cdkDropListDropped)="drop($event, fields)">
<!-- <tr *ngFor="let data of fields, let i = index" cdkDrag> -->
<tr *ngFor="let data of basicTable.data, let i = index" cdkDrag>
<td>值{{ i + 1 }}</td>
<td>{{ data.fields }}</td>
<td>
<a (click)="deleteRow(item, i, index, data.$sortOperation)">删除</a>
</td>
</tr>
</tbody>
</nz-table>
对表格行数据遍历有2种写法,如下:
// 写法1
<tr *ngFor="let data of fields, let i = index" cdkDrag>
// 写法2
<tr *ngFor="let data of basicTable.data, let i = index" cdkDrag>
如果采用写法1
写法是官网示例的写法之一
点击新增时,数据push进去了,但是表格没有新增一条
addRow(item) {
item.fields.push({
...cloneDeep(fieldsGroup),
add_id: addId,
});
}
但使用如下写法,点击新增时,数据push进去了,但是表格没有成功显示新增
addRow(item) {
item.fields = [
...item.groupByFields,
{
...cloneDeep(fieldsGroup),
add_id: addId,
},
];
}
同理删除的时候也是如此:
点击删除按钮的时候,使用splice删除一行,该数据已经删除,但表格页面数据没有消失
deleteRow(item, index, tableIndex, sortOperation) {
item.fields.splice(index, 1);
}
但是如果使用filter,将过滤后的结果重新赋值,表格成功删除一条
deleteRow(item, index, tableIndex, sortOperation) {
item.fields = item.fields.filter(item => item.$sortOperation !== sortOperation);
}
另外,如果只用表格拖拽功能时,写法1也不能成功拖拽表格顺序。
如果采用写法2
如果采用写法2,上面的2中写法都可以实现效果。
分析
查找ng-zorro-antd源码,发现其中是这么写的:当nzData发生变化的时候重新渲染。
ngOnChanges(changes: SimpleChanges): void {
if (nzData) {
this.nzData = this.nzData || [];
this.nzTableDataService.updateListOfData(this.nzData);
}
}
查找发现
当Angular检查组件的输入属性以进行更改时,它(基本上)===使用脏检查。对于数组,这意味着对数组引用(仅)进行脏检查。由于引用没有改变,ngOnChanges()因此不会被调用。
OnChanges只对输入的基本数据类型起作用,而引用数据类型不会触发OnChanges方法。
当使用写法1的时候,由于是引用数据类型,对表格行数据进行操作,不会触发OnChanges方法,是不会触发表格组件的重新渲染的,但是重新赋值改变了nzData的引用,会触发OnChanges方法。
ng-zorro-antd官网使用写法1是因为其数据结构简单,这个问题就不会出现。在自己的工作中,数据层级多,问题出现。