Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use the MatTableDataSource with an observable?

Tags:

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;
    });
}
like image 803
Christoph Hummler Avatar asked Sep 03 '19 11:09

Christoph Hummler


People also ask

What is MatTableDataSource?

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.


3 Answers

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;     }); } 
like image 116
Stuart Hallows Avatar answered Nov 20 '22 00:11

Stuart Hallows


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.

like image 42
H3AR7B3A7 Avatar answered Nov 20 '22 02:11

H3AR7B3A7


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

like image 21
burasuk Avatar answered Nov 20 '22 00:11

burasuk