Reputation: 40157
I am using the MatTable in which the first row is pre-populated with a MatAutocomplete input control that is bound to a dynamic data call. Everything works as expected there.
I have an "Add Row" button that calls a method to update the table with a new row. The issue I'm trying to resolve or better understand is that it appears that when the new row is added, all the previous rows get reloaded even though their data has not changed.
I'm using onPush changedetection. Anyone know if its possible to optimize the matTable to not rerender previously rendered rows?
addRow(event: any) {
this.clearSort();
this.clearFilter(undefined);
const currentData = cloneDeep(this.formArrayValues);
currentData.push(this.emptyRowFromColumnDef); // Append new row to END of table
this.updateTableData(currentData);
if (this.paginationEnable && this.paginator) {
// move table paging to last page to see newly added row. setTimeout helps avoid sync delay
timer().subscribe(() => this.paginator.lastPage());
}
timer(1).subscribe(() => this.changeDetectorRef.markForCheck());
event.preventDefault();
}
get emptyRowFromColumnDef(): any {
const item = {};
const columns = get(this.tableConfig, `columns`, []);
const columnTypes = get(this.tableConfig, `columnTypes`, {});
if (columns.length) {
for (let i = 0; i < columns.length; i++) {
if (columns[i] === this.SELECTION_COLUMN_NAME) {
item[columns[i]] = true;
} else {
// Todo - Set this to the correct default type. Should be able to use tableConfig
item[columns[i]] = this.defaultEmptyValueByType(columns[i], columnTypes[columns[i]]);
}
}
}
return item;
}
get formArrayValues(): any[] {
return this.formArray.getRawValue();
}
get formArray(): FormArray {
return <FormArray>this.formControl;
}
updateTableData(datasource: any) {
this.resetFilterIfActive();
const useData = this.defaultEmptyColumnData(this._limitDataByMode(datasource));
this.data = useData;
if (this.paginationEnable) {
this.paginatorLength = useData.length || 0;
}
this.syncDatasourceToFormControl();
this.renderRows();
}
syncDatasourceToFormControl() {
if (!['builder'].includes(this.jsf.mode)) {
if (this.formArray && isFunction(this.formArray.clear)) {
this.formArray.clear();
}
let data = this.data || [];
this.formArrayUpdateAll();
if (this.options.rowSelection) {
data = this.defaultUndefinedSelection(data);
}
if (this.formArray) {
this.bindDataToForm(data);
this.renderRows();
this.testLogicSyncChanges();
}
}
}
formArrayUpdateAll() {
const dataTotal = (this.data || []).length;
const $refNode = this._getRefNode();
if ($refNode) {
$refNode.options.tableItem = true;
for (let i = 0; i < dataTotal; i++) {
const index = i + 1;
const $ref = {
layoutNode: $refNode,
layoutIndex: this.layoutIndex.concat(index),
dataIndex: this.dataIndex.concat(index)
};
this.jsf.addItem($ref);
}
}
}
Upvotes: 0
Views: 441
Reputation: 36
I'm assuming by 'reloaded' you mean 'rerendered'. You might be able to use trackBy. From material angular docs:
To improve performance, a trackBy function can be provided to the table similar to Angular’s ngFor trackBy. This informs the table how to uniquely identify rows to track how the data changes with each update.
Upvotes: 1