I am using the mat-table and I am trying to use the MatTableDataSource with an observable (I get the data from a web service), but I don't know how to configure the MatTableDataSource to use an observable instead of an array.
Is the only solution to this problem, to subscribe to the observable in the ngOnInit method and always create a new MatTableDataSource when new data arrives?
This is what I have until now, but I don't know if this is the correct solution for working with the MatTableDataSource with an observable.
dataSource: MatTableDataSource<Thing>;
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
@ViewChild(MatSort, { static: true }) sort: MatSort;
ngOnInit() {
getThings().subscribe(things => {
this.dataSource = new MatTableDataSource(things);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
});
}
MatTableDataSource. Data source that accepts a client-side data array and includes native support of filtering, sorting (using MatSort), and pagination (using MatPaginator). Allows for sort customization by overriding sortingDataAccessor, which defines how data properties are accessed.
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; }); }
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...
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With