Skip to content

Commit b366222

Browse files
committed
fix(material/table): better handling of invalid data
The table data source is set up to expect an array and will throw a cryptic error down the line if the value is anything different. While typings should be enough to enforce this, if the value comes from somewhere in the view it may not get caught. Since the effort for handling it on our end is minimal, these changes add some logic that fall back to an empty array if the value is invalid. Fixes #18859.
1 parent 4f8e87e commit b366222

File tree

3 files changed

+79
-0
lines changed

3 files changed

+79
-0
lines changed

src/material-experimental/mdc-table/table.spec.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,45 @@ describe('MDC-based MatTable', () => {
280280
]);
281281
});
282282

283+
it('should fall back to empty table if invalid data is passed in', () => {
284+
component.underlyingDataSource.addData();
285+
fixture.detectChanges();
286+
expectTableToMatchContent(tableElement, [
287+
['Column A', 'Column B', 'Column C'],
288+
['a_1', 'b_1', 'c_1'],
289+
['a_2', 'b_2', 'c_2'],
290+
['a_3', 'b_3', 'c_3'],
291+
['a_4', 'b_4', 'c_4'],
292+
['Footer A', 'Footer B', 'Footer C'],
293+
]);
294+
295+
dataSource.data = null!;
296+
fixture.detectChanges();
297+
expectTableToMatchContent(tableElement, [
298+
['Column A', 'Column B', 'Column C'],
299+
['Footer A', 'Footer B', 'Footer C'],
300+
]);
301+
302+
component.underlyingDataSource.addData();
303+
fixture.detectChanges();
304+
expectTableToMatchContent(tableElement, [
305+
['Column A', 'Column B', 'Column C'],
306+
['a_1', 'b_1', 'c_1'],
307+
['a_2', 'b_2', 'c_2'],
308+
['a_3', 'b_3', 'c_3'],
309+
['a_4', 'b_4', 'c_4'],
310+
['a_5', 'b_5', 'c_5'],
311+
['Footer A', 'Footer B', 'Footer C'],
312+
]);
313+
314+
dataSource.data = {} as any;
315+
fixture.detectChanges();
316+
expectTableToMatchContent(tableElement, [
317+
['Column A', 'Column B', 'Column C'],
318+
['Footer A', 'Footer B', 'Footer C'],
319+
]);
320+
});
321+
283322
it('should update the page index when switching to a smaller data set from a page',
284323
fakeAsync(() => {
285324
// Add 20 rows so we can switch pages.

src/material/table/table-data-source.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export class _MatTableDataSource<T, P extends Paginator> extends DataSource<T> {
6666
/** Array of data that should be rendered by the table, where each object represents one row. */
6767
get data() { return this._data.value; }
6868
set data(data: T[]) {
69+
data = Array.isArray(data) ? data : [];
6970
this._data.next(data);
7071
// Normally the `filteredData` is updated by the re-render
7172
// subscription, but that won't happen if it's inactive.

src/material/table/table.spec.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,45 @@ describe('MatTable', () => {
266266
]);
267267
});
268268

269+
it('should fall back to empty table if invalid data is passed in', () => {
270+
component.underlyingDataSource.addData();
271+
fixture.detectChanges();
272+
expectTableToMatchContent(tableElement, [
273+
['Column A', 'Column B', 'Column C'],
274+
['a_1', 'b_1', 'c_1'],
275+
['a_2', 'b_2', 'c_2'],
276+
['a_3', 'b_3', 'c_3'],
277+
['a_4', 'b_4', 'c_4'],
278+
['Footer A', 'Footer B', 'Footer C'],
279+
]);
280+
281+
dataSource.data = null!;
282+
fixture.detectChanges();
283+
expectTableToMatchContent(tableElement, [
284+
['Column A', 'Column B', 'Column C'],
285+
['Footer A', 'Footer B', 'Footer C'],
286+
]);
287+
288+
component.underlyingDataSource.addData();
289+
fixture.detectChanges();
290+
expectTableToMatchContent(tableElement, [
291+
['Column A', 'Column B', 'Column C'],
292+
['a_1', 'b_1', 'c_1'],
293+
['a_2', 'b_2', 'c_2'],
294+
['a_3', 'b_3', 'c_3'],
295+
['a_4', 'b_4', 'c_4'],
296+
['a_5', 'b_5', 'c_5'],
297+
['Footer A', 'Footer B', 'Footer C'],
298+
]);
299+
300+
dataSource.data = {} as any;
301+
fixture.detectChanges();
302+
expectTableToMatchContent(tableElement, [
303+
['Column A', 'Column B', 'Column C'],
304+
['Footer A', 'Footer B', 'Footer C'],
305+
]);
306+
});
307+
269308
it('should update the page index when switching to a smaller data set from a page',
270309
fakeAsync(() => {
271310
// Add 20 rows so we can switch pages.

0 commit comments

Comments
 (0)