Skip to content

feat(material/table): add API to force datasource to update #30896

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion src/material/table/table-data-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ export class MatTableDataSource<T, P extends MatPaginator = MatPaginator> extend
/** Used to react to internal changes of the paginator that are made by the data source itself. */
private readonly _internalPageChanges = new Subject<void>();

/** Stream that will force the data source to emit new data. */
private readonly _forceEmit = new BehaviorSubject<boolean>(true);

/**
* Subscription to the changes that should trigger an update to the table's rendered rows, such
* as filtering, sorting, pagination, or base data changes.
Expand Down Expand Up @@ -243,6 +246,16 @@ export class MatTableDataSource<T, P extends MatPaginator = MatPaginator> extend
this._updateChangeSubscription();
}

/**
* Forces the data source to emit data to the table based on the current state of the sort
* and paginator. This may be necessary if the state of the paginator or sort components have
* been changed programmatically through their Inputs, which do not emit Output events that
* would otherwise notify a change.
*/
forceEmit(): void {
this._forceEmit.next(true);
}

/**
* Subscribe to changes that should trigger an update to the table's rendered rows. When the
* changes occur, process the current state of the filter, sort, and pagination along with
Expand All @@ -267,7 +280,7 @@ export class MatTableDataSource<T, P extends MatPaginator = MatPaginator> extend
: observableOf(null);
const dataStream = this._data;
// Watch for base data or filter changes to provide a filtered set of data.
const filteredData = combineLatest([dataStream, this._filter]).pipe(
const filteredData = combineLatest([dataStream, this._filter, this._forceEmit]).pipe(
map(([data]) => this._filterData(data)),
);
// Watch for filtered data or sort changes to provide an ordered set of data.
Expand Down
44 changes: 35 additions & 9 deletions src/material/table/table.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -542,15 +542,26 @@ describe('MatTable', () => {
for (let i = 0; i < 100; i++) {
component.underlyingDataSource.addData();
}
fixture.detectChanges();
flushMicrotasks(); // Resolve promise that updates paginator's length
expectTableToMatchContent(tableElement, [
['Column A', 'Column B', 'Column C'],
const firstPage = [
['a_1', 'b_1', 'c_1'],
['a_2', 'b_2', 'c_2'],
['a_3', 'b_3', 'c_3'],
['a_4', 'b_4', 'c_4'],
['a_5', 'b_5', 'c_5'],
];
const secondPage = [
['a_6', 'b_6', 'c_6'],
['a_7', 'b_7', 'c_7'],
['a_8', 'b_8', 'c_8'],
['a_9', 'b_9', 'c_9'],
['a_10', 'b_10', 'c_10'],
];

fixture.detectChanges();
flushMicrotasks(); // Resolve promise that updates paginator's length
expectTableToMatchContent(tableElement, [
['Column A', 'Column B', 'Column C'],
...firstPage,
['Footer A', 'Footer B', 'Footer C'],
]);

Expand All @@ -559,11 +570,26 @@ describe('MatTable', () => {
fixture.detectChanges();
expectTableToMatchContent(tableElement, [
['Column A', 'Column B', 'Column C'],
['a_6', 'b_6', 'c_6'],
['a_7', 'b_7', 'c_7'],
['a_8', 'b_8', 'c_8'],
['a_9', 'b_9', 'c_9'],
['a_10', 'b_10', 'c_10'],
...secondPage,
['Footer A', 'Footer B', 'Footer C'],
]);

component.paginator.pageIndex = 0;
fixture.detectChanges();
// Expect no changes from before since the data source has not been told to check and
// the paginator did not send an Output based on the change.
expectTableToMatchContent(tableElement, [
['Column A', 'Column B', 'Column C'],
...secondPage,
['Footer A', 'Footer B', 'Footer C'],
]);

// Use data source's `forceEmit` to update data based on the latest state in the paginator.
component.dataSource.forceEmit();
fixture.detectChanges();
expectTableToMatchContent(tableElement, [
['Column A', 'Column B', 'Column C'],
...firstPage,
['Footer A', 'Footer B', 'Footer C'],
]);
}));
Expand Down
Loading