Skip to content

Commit 8511b74

Browse files
kryshaccrisbeto
authored andcommitted
fix(cdk/table): the CdkNoDataRow directive does not render in the OnPush strategy (#27687)
Fixes a bug in the Angular CDK `table` component where the CdkNoDataRow directive with binding data is not rendered correctly when the parent component has the OnPush strategy set (cherry picked from commit ca9c490)
1 parent 1d984f3 commit 8511b74

File tree

2 files changed

+75
-4
lines changed

2 files changed

+75
-4
lines changed

src/cdk/table/table.spec.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
Type,
1010
ViewChild,
1111
AfterViewInit,
12+
ChangeDetectionStrategy,
1213
} from '@angular/core';
1314
import {ComponentFixture, fakeAsync, flush, flushMicrotasks, TestBed} from '@angular/core/testing';
1415
import {BehaviorSubject, combineLatest, Observable, of as observableOf} from 'rxjs';
@@ -1913,6 +1914,20 @@ describe('CdkTable', () => {
19131914
expect(cellElement.classList.contains('custom-cell-class-even')).toBe(true);
19141915
expect(cellElement.classList.contains('custom-cell-class-odd')).toBe(false);
19151916
});
1917+
1918+
it('should be able to show a message when no data is being displayed in the strategy ChangeDetectionOnPush', () => {
1919+
setupTableTestApp(WrapNativeHtmlTableAppOnPush, [NativeHtmlTableAppOnPush]);
1920+
1921+
expect(tableElement.querySelector('.cdk-no-data-row')).toBeFalsy();
1922+
1923+
component.dataSource.data = [];
1924+
1925+
fixture.detectChanges();
1926+
1927+
const noDataRow = tableElement.querySelector('.cdk-no-data-row')!;
1928+
expect(noDataRow).toBeTruthy();
1929+
expect(noDataRow.getAttribute('colspan')).toEqual('3');
1930+
});
19161931
});
19171932

19181933
interface TestData {
@@ -3011,6 +3026,48 @@ class TableWithIndirectDescendantDefs {
30113026
dataSource = new FakeDataSource();
30123027
}
30133028

3029+
@Component({
3030+
selector: 'cdk-table-change-detection-on-push',
3031+
template: `
3032+
<table cdk-table [dataSource]="dataSource">
3033+
<ng-container cdkColumnDef="column_a">
3034+
<th cdk-header-cell *cdkHeaderCellDef> Column A</th>
3035+
<td cdk-cell *cdkCellDef="let row"> {{row.a}}</td>
3036+
</ng-container>
3037+
3038+
<ng-container cdkColumnDef="column_b">
3039+
<th cdk-header-cell *cdkHeaderCellDef> Column B</th>
3040+
<td cdk-cell *cdkCellDef="let row"> {{row.b}}</td>
3041+
</ng-container>
3042+
3043+
<ng-container cdkColumnDef="column_c">
3044+
<th cdk-header-cell *cdkHeaderCellDef> Column C</th>
3045+
<td cdk-cell *cdkCellDef="let row"> {{row.c}}</td>
3046+
</ng-container>
3047+
3048+
<tr cdk-header-row *cdkHeaderRowDef="columnsToRender"></tr>
3049+
<tr cdk-row *cdkRowDef="let row; columns: columnsToRender" class="customRowClass"></tr>
3050+
<tr *cdkNoDataRow [attr.colspan]="columnsToRender.length">
3051+
<td>No data</td>
3052+
</tr>
3053+
</table>
3054+
`,
3055+
changeDetection: ChangeDetectionStrategy.OnPush,
3056+
})
3057+
class NativeHtmlTableAppOnPush {
3058+
@Input() dataSource: Observable<TestData[]> | null = null;
3059+
columnsToRender = ['column_a', 'column_b', 'column_c'];
3060+
}
3061+
3062+
@Component({
3063+
template: `
3064+
<cdk-table-change-detection-on-push [dataSource]="dataSource"></cdk-table-change-detection-on-push>
3065+
`,
3066+
})
3067+
class WrapNativeHtmlTableAppOnPush {
3068+
dataSource: FakeDataSource = new FakeDataSource();
3069+
}
3070+
30143071
function getElements(element: Element, query: string): HTMLElement[] {
30153072
return [].slice.call(element.querySelectorAll(query));
30163073
}

src/cdk/table/table.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,10 @@ export type CdkTableDataSourceInput<T> = readonly T[] | DataSource<T> | Observab
110110
*/
111111
@Directive({selector: '[rowOutlet]'})
112112
export class DataRowOutlet implements RowOutlet {
113-
constructor(public viewContainer: ViewContainerRef, public elementRef: ElementRef) {}
113+
constructor(
114+
public viewContainer: ViewContainerRef,
115+
public elementRef: ElementRef,
116+
) {}
114117
}
115118

116119
/**
@@ -119,7 +122,10 @@ export class DataRowOutlet implements RowOutlet {
119122
*/
120123
@Directive({selector: '[headerRowOutlet]'})
121124
export class HeaderRowOutlet implements RowOutlet {
122-
constructor(public viewContainer: ViewContainerRef, public elementRef: ElementRef) {}
125+
constructor(
126+
public viewContainer: ViewContainerRef,
127+
public elementRef: ElementRef,
128+
) {}
123129
}
124130

125131
/**
@@ -128,7 +134,10 @@ export class HeaderRowOutlet implements RowOutlet {
128134
*/
129135
@Directive({selector: '[footerRowOutlet]'})
130136
export class FooterRowOutlet implements RowOutlet {
131-
constructor(public viewContainer: ViewContainerRef, public elementRef: ElementRef) {}
137+
constructor(
138+
public viewContainer: ViewContainerRef,
139+
public elementRef: ElementRef,
140+
) {}
132141
}
133142

134143
/**
@@ -138,7 +147,10 @@ export class FooterRowOutlet implements RowOutlet {
138147
*/
139148
@Directive({selector: '[noDataRowOutlet]'})
140149
export class NoDataRowOutlet implements RowOutlet {
141-
constructor(public viewContainer: ViewContainerRef, public elementRef: ElementRef) {}
150+
constructor(
151+
public viewContainer: ViewContainerRef,
152+
public elementRef: ElementRef,
153+
) {}
142154
}
143155

144156
/**
@@ -1337,6 +1349,8 @@ export class CdkTable<T> implements AfterContentChecked, CollectionViewer, OnDes
13371349
}
13381350

13391351
this._isShowingNoDataRow = shouldShow;
1352+
1353+
this._changeDetectorRef.markForCheck();
13401354
}
13411355
}
13421356

0 commit comments

Comments
 (0)