2

I'm currently learning to use Angular with Material UI and want to display a table. I'm loading my data through an combination of In-Memory DB and HTTP Interception. My problem is that my table does not update when it receives new data.

For the table I use the generated component provided by Angular Material. When I update my table data I can see during debugging that the Array the table holds is updated with the desired data. However, only if I change sorting or pagination the data is actually refreshed in my table.

For some reason the observable in connect() (see below) is not called when my data changes. What am I missing that is needed to trigger the table refreshment?

TableComponent:

export class TableComponent implements AfterViewInit {
  @ViewChild(MatPaginator) paginator!: MatPaginator;
  @ViewChild(MatSort) sort!: MatSort;
  @ViewChild(MatTable) table!: MatTable<TableItem>;
  dataSource: TableDataSource;

  /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
  displayedColumns = ['id', 'name'];

  constructor(private tableService: TableService) {
    this.dataSource = new TableDataSource(tableService);
  }

  isActive = false; // does not interact with table!

  ngAfterViewInit(): void {
    this.getTableData();
    this.dataSource.sort = this.sort;
    this.dataSource.paginator = this.paginator;
    this.table.dataSource = this.dataSource;
  }

  public getTableData():void{
    this.dataSource.getTableData();
  }

TableDataSource:

export class TableDataSource extends DataSource<TableItem> {
  data: TableItem[] = [];
  paginator: MatPaginator | undefined;
  sort: MatSort | undefined;

  constructor(private tableService: TableService) {
    super();
  }

  /**
   * Connect this data source to the table. The table will only update when
   * the returned stream emits new items.
   * @returns A stream of the items to be rendered.
   */
  connect(): Observable<TableItem[]> {
    if (this.paginator && this.sort) {
      // Combine everything that affects the rendered data into one update
      // stream for the data-table to consume.
      return merge(observableOf(this.data), this.paginator.page, this.sort.sortChange)
        .pipe(map(() => {
          return this.getPagedData(this.getSortedData([...this.data ]));
        }));
    } else {
      throw Error('Please set the paginator and sort on the data source before connecting.');
    }
  }

[....]

public getTableData():void{
    this.tableService.getTableItems()
    .subscribe(items => {
      this.data = items;
    });
  }
hullunist
  • 1,117
  • 2
  • 11
  • 31
  • Maybe instead of subscripting in the datasource. Use mergemap on it and do your mappings and return the whole thing. Then the template will do the subscribing – Henrik Bøgelund Lavstsen Apr 15 '21 at 11:10
  • @HenrikBøgelundLavstsen I'll give it a try but to me it seems like I just somehow need to manually tell the table to redraw since when I add elements the pager shows me the correct amount of elements. – hullunist Apr 15 '21 at 11:29

1 Answers1

0

Try to do below thing

@ViewChild(MatTable) table!: MatTable<any>;

and once u receive data do

this.table.renderRows();
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
Suhail
  • 1
  • 1