+
+
+
+
+
+
+
+
+
+
+
+
ID
@@ -258,9 +281,11 @@
{{row.color}}
-
-
-
+
+
+ ();
wasExpanded = new Set();
- filter = new FormControl();
+ matTableDataSourceColumns = ['select', 'userId', 'userName', 'progress', 'color'];
+ selection = new SelectionModel(true, []);
+
+ @ViewChild('filter') filter: ElementRef;
dynamicColumnDefs: any[] = [];
dynamicColumnIds: string[] = [];
@@ -62,7 +69,6 @@ export class TableDemo {
};
this.matTableDataSource.filterPredicate =
(data: UserData, filter: string) => data.name.indexOf(filter) != -1;
- this.filter.valueChanges.subscribe(filter => this.matTableDataSource!.filter = filter);
}
ngAfterViewInit() {
@@ -74,6 +80,43 @@ export class TableDemo {
ngOnInit() {
this.connect();
+ Observable.fromEvent(this.filter.nativeElement, 'keyup')
+ .debounceTime(150)
+ .distinctUntilChanged()
+ .subscribe(() => {
+ this.paginatorForDataSource.pageIndex = 0;
+ this.matTableDataSource.filter = this.filter.nativeElement.value;
+ });
+ }
+
+ /** Whether all filtered rows are selected. */
+ isAllFilteredRowsSelected() {
+ return this.matTableDataSource.filteredData.every(data => this.selection.isSelected(data));
+ }
+
+ /** Whether the selection it totally matches the filtered rows. */
+ isMasterToggleChecked() {
+ return this.selection.hasValue() &&
+ this.isAllFilteredRowsSelected() &&
+ this.selection.selected.length >= this.matTableDataSource.filteredData.length;
+ }
+
+ /**
+ * Whether there is a selection that doesn't capture all the
+ * filtered rows there are no filtered rows displayed.
+ */
+ isMasterToggleIndeterminate() {
+ return this.selection.hasValue() &&
+ (!this.isAllFilteredRowsSelected() || !this.matTableDataSource.filteredData.length);
+ }
+
+ /** Selects all filtered rows if they are not all selected; otherwise clear selection. */
+ masterToggle() {
+ if (this.isMasterToggleChecked()) {
+ this.selection.clear();
+ } else {
+ this.matTableDataSource.filteredData.forEach(data => this.selection.select(data));
+ }
}
addDynamicColumnDef() {
diff --git a/src/lib/table/table-data-source.ts b/src/lib/table/table-data-source.ts
index 98fbd4b82ba..f45e427afff 100644
--- a/src/lib/table/table-data-source.ts
+++ b/src/lib/table/table-data-source.ts
@@ -40,6 +40,14 @@ export class MatTableDataSource implements DataSource {
*/
_renderChangesSubscription: Subscription;
+ /**
+ * The filtered set of data that has been matched by the filter string, or all the data if there
+ * is no filter. Useful for knowing the set of data the table represents.
+ * For example, a 'selectAll()' function would likely want to select the set of filtered data
+ * shown to the user rather than all the data.
+ */
+ filteredData: T[];
+
/** Array of data that should be rendered by the table, where each object represents one row. */
set data(data: T[]) { this._data.next(data); }
get data() { return this._data.value; }
@@ -164,12 +172,12 @@ export class MatTableDataSource implements DataSource {
// If there is a filter string, filter out data that does not contain it.
// Each data object is converted to a string using the function defined by filterTermAccessor.
// May be overriden for customization.
- const filteredData =
+ this.filteredData =
!this.filter ? data : data.filter(obj => this.filterPredicate(obj, this.filter));
- if (this.paginator) { this._updatePaginator(filteredData.length); }
+ if (this.paginator) { this._updatePaginator(this.filteredData.length); }
- return filteredData;
+ return this.filteredData;
}
/**
diff --git a/src/lib/table/table.spec.ts b/src/lib/table/table.spec.ts
index b4b398f3230..2b2f1e360f6 100644
--- a/src/lib/table/table.spec.ts
+++ b/src/lib/table/table.spec.ts
@@ -102,16 +102,21 @@ describe('MatTable', () => {
// Change filter to a_1, should match one row
dataSource.filter = 'a_1';
fixture.detectChanges();
+ expect(dataSource.filteredData.length).toBe(1);
+ expect(dataSource.filteredData[0]).toBe(dataSource.data[0]);
expectTableToMatchContent(tableElement, [
['Column A', 'Column B', 'Column C'],
['a_1', 'b_1', 'c_1'],
]);
+
flushMicrotasks(); // Resolve promise that updates paginator's length
expect(dataSource.paginator!.length).toBe(1);
// Change filter to ' A_2 ', should match one row (ignores case and whitespace)
dataSource.filter = ' A_2 ';
fixture.detectChanges();
+ expect(dataSource.filteredData.length).toBe(1);
+ expect(dataSource.filteredData[0]).toBe(dataSource.data[1]);
expectTableToMatchContent(tableElement, [
['Column A', 'Column B', 'Column C'],
['a_2', 'b_2', 'c_2'],
@@ -120,6 +125,10 @@ describe('MatTable', () => {
// Change filter to empty string, should match all rows
dataSource.filter = '';
fixture.detectChanges();
+ expect(dataSource.filteredData.length).toBe(3);
+ expect(dataSource.filteredData[0]).toBe(dataSource.data[0]);
+ expect(dataSource.filteredData[1]).toBe(dataSource.data[1]);
+ expect(dataSource.filteredData[2]).toBe(dataSource.data[2]);
expectTableToMatchContent(tableElement, [
['Column A', 'Column B', 'Column C'],
['a_1', 'b_1', 'c_1'],