How to use the MatTableDataSource with an observable?
Use MatTableDataSource as Observable
You can just pipe
your observable:
thingsAsMatTableDataSource$: Observable<MatTableDataSource<Thing>> =
getThings().pipe(
map(things => {
const dataSource = new MatTableDataSource<Thing>();
dataSource.data = things;
return dataSource;
}));
You can use an async pipe on your observable in the template:
[dataSource]="thingsAsMatTableDataSource$ | async"
This way you do not have to subscribe, and can still enjoy mat-table sorting etc...
Prevent Repeated Constructor Calls
Just instantiate it once as a private member and use that instead:
private dataSource = new MatTableDataSource<Thing>();
thingsAsMatTableDataSource$: Observable<MatTableDataSource<Thing>> =
getThings().pipe(
map(things => {
const dataSource = this.dataSource;
dataSource.data = things
return dataSource;
}));
Here's a simple example on Stackblitz.
this is a workaround, because MatTableDataSource doesn't support Observable as data source
import { MatTableDataSource } from '@angular/material';
import { Observable, Subscription } from 'rxjs';
import { SomeInterface} from './some.interface';
export class CustomDataSource extends MatTableDataSource<SomeInterface> {
private collection: SomeInterface[] = [];
private collection$: Subscription;
constructor(collection: Observable<SomeInterface[]>) {
super();
this.collection$ = collection.subscribe(data => {
this.data = data; // here you have to adjust the behavior as needed
});
}
disconnect() {
this.collection$.unsubscribe();
super.disconnect();
}
}
then in component:
dataSource: CustomDataSource;
ngOnInit(): void {
const observableData$ = getData();
this.dataSource = new CustomDataSource(observableData$);
// this.dataSource.sort = this.sort; // add sorting or filter
}
example: stackblitz
You can use an observable too, just (*)
[dataSource]="dataSource|async"
(*) really you needn't use the pipe async
See an example in stackblitz, where I replace the first example of the doc by
dataSource = of(ELEMENT_DATA).pipe(delay(1000));
You should be able to new up the MatTableDataSource
once at the class level and then use the data
setter in ngOnInit
.
dataSource = new MatTableDataSource<Thing>();
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
@ViewChild(MatSort, { static: true }) sort: MatSort;
ngOnInit() {
getThings().subscribe(things => {
this.dataSource.data = things;
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
});
}