diff --git a/src/cdk/table/table.spec.ts b/src/cdk/table/table.spec.ts index 08b792838694..d321a9d31dd6 100644 --- a/src/cdk/table/table.spec.ts +++ b/src/cdk/table/table.spec.ts @@ -13,6 +13,7 @@ import { Type, ViewChild, inject, + TrackByFunction, } from '@angular/core'; import {By} from '@angular/platform-browser'; import {ComponentFixture, TestBed, fakeAsync, flush, waitForAsync} from '@angular/core/testing'; @@ -1995,6 +1996,35 @@ describe('CdkTable', () => { expect(noDataRow).toBeTruthy(); expect(noDataRow.getAttribute('colspan')).toEqual('3'); }); + + it('should properly update table content when data changes in OnPush component with track by instance', () => { + setupTableTestApp(WrapNativeTrackByHtmlTableAppOnPush); + + const data = component.dataSource.data; + + expectTableToMatchContent(tableElement, [ + ['Column A', 'Column B', 'Column C'], + [data[0].a, data[0].b, data[0].c], + [data[1].a, data[1].b, data[1].c], + [data[2].a, data[2].b, data[2].c], + ]); + + component.dataSource.data = component.dataSource.data.map((data: TestData) => ({ + ...data, + b: `${data.b}-updated`, + })); + + fixture.detectChanges(); + + const newData = component.dataSource.data; + + expectTableToMatchContent(tableElement, [ + ['Column A', 'Column B', 'Column C'], + [newData[0].a, newData[0].b, newData[0].c], + [newData[1].a, newData[1].b, newData[1].c], + [newData[2].a, newData[2].b, newData[2].c], + ]); + }); }); interface TestData { @@ -3135,7 +3165,7 @@ class TableWithIndirectDescendantDefs { @Component({ selector: 'cdk-table-change-detection-on-push', template: ` - +
@@ -3163,6 +3193,7 @@ class TableWithIndirectDescendantDefs { }) class NativeHtmlTableAppOnPush { @Input() dataSource: Observable | null = null; + @Input() trackBy: TrackByFunction | undefined; columnsToRender = ['column_a', 'column_b', 'column_c']; } @@ -3176,6 +3207,17 @@ class WrapNativeHtmlTableAppOnPush { dataSource: FakeDataSource = new FakeDataSource(); } +@Component({ + template: ` + + `, + imports: [NativeHtmlTableAppOnPush], +}) +class WrapNativeTrackByHtmlTableAppOnPush { + dataSource: FakeDataSource = new FakeDataSource(); + trackBy: TrackByFunction = (index: number, data: TestData) => data.a; +} + function getElements(element: Element, query: string): HTMLElement[] { return [].slice.call(element.querySelectorAll(query)); } diff --git a/src/cdk/table/table.ts b/src/cdk/table/table.ts index a8ffcfabcbeb..e8f23cc94d6d 100644 --- a/src/cdk/table/table.ts +++ b/src/cdk/table/table.ts @@ -682,6 +682,7 @@ export class CdkTable if (!changes) { this._updateNoDataRow(); this.contentChanged.next(); + this._changeDetectorRef.markForCheck(); return; } const viewContainer = this._rowOutlet.viewContainer; @@ -716,6 +717,7 @@ export class CdkTable this.contentChanged.next(); this.updateStickyColumnStyles(); + this._changeDetectorRef.markForCheck(); } /** Adds a column definition that was not included as part of the content children. */
Column A {{row.a}}