243

I am using a mat-table to list the content of the users chosen languages. They can also add new languages using dialog panel. After they added a language and returned back. I want my datasource to refresh to show the changes they made.

I initialize the datastore by getting user data from a service and passing that into a datasource in the refresh method.

Language.component.ts

import { Component, OnInit } from '@angular/core';
import { LanguageModel, LANGUAGE_DATA } from '../../../../models/language.model';
import { LanguageAddComponent } from './language-add/language-add.component';
import { AuthService } from '../../../../services/auth.service';
import { LanguageDataSource } from './language-data-source';
import { LevelbarComponent } from '../../../../directives/levelbar/levelbar.component';
import { DataSource } from '@angular/cdk/collections';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import { MatSnackBar, MatDialog } from '@angular/material';

@Component({
  selector: 'app-language',
  templateUrl: './language.component.html',
  styleUrls: ['./language.component.scss']
})
export class LanguageComponent implements OnInit {

  displayedColumns = ['name', 'native', 'code', 'level'];
  teachDS: any;
  user: any;

  constructor(private authService: AuthService, private dialog: MatDialog) { }

  ngOnInit() {
    this.refresh();
  }

  add() {
    this.dialog.open(LanguageAddComponent, {
      data: { user: this.user },
    }).afterClosed().subscribe(result => {
      this.refresh();
    });
  }

  refresh() {
    this.authService.getAuthenticatedUser().subscribe((res) => {
      this.user = res;
      this.teachDS = new LanguageDataSource(this.user.profile.languages.teach);   
    });
  }
}

language-data-source.ts

import {MatPaginator, MatSort} from '@angular/material';
import {DataSource} from '@angular/cdk/collections';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/merge';
import 'rxjs/add/operator/map';

export class LanguageDataSource extends DataSource<any> {

  constructor(private languages) {
    super();
  }

  connect(): Observable<any> {
    return Observable.of(this.languages);
  }

  disconnect() {
    // No-op
  }

}

So I have tried to call a refresh method where I get the user from the backend again and then I reinitialize the data source. However this does not work, no changes are occurring.

3
  • 1
    If you want to trigger the change "from the data source", please have a look at stackoverflow.com/questions/47897694/… Commented Jan 12, 2019 at 14:46
  • Event emmiters can be use in this case. stackoverflow.com/a/44858648/8300620 Commented Sep 17, 2019 at 7:07
  • 2
    The fact that there are 29 answers, and they are all some sort of hack to force data change detection to fire, shows how poorly angular/material handles this. Commented Feb 25, 2024 at 19:27

28 Answers 28

162

I don't know if the ChangeDetectorRef was required when the question was created, but now this is enough:

import { MatTableDataSource } from '@angular/material/table';

// ...

dataSource = new MatTableDataSource<MyDataType>();

refresh() {
  this.myService.doSomething().subscribe((data: MyDataType[]) => {
    this.dataSource.data = data;
  }
}

Example:
StackBlitz

Sign up to request clarification or add additional context in comments.

4 Comments

While this solution does in fact work, it does mess up the material paginator if the element is added somewhere other than the first page of results. I understand that that is beyond the scope of this question but since the two are related, do you happen to have a quick solution to that problem that you could add to your answer?
@Knight I think you have to assign the Paginator to the MatTableDataSource.paginator property after the Paginator's view has been initialized. See the description of paginator property here: material.angular.io/components/table/api#MatTableDataSource
Good reference. I hadn't spotted that in the docs before. Thanks!
@MA-Maddin can you be more specific on how to do it? example?
84

Trigger a change detection by using ChangeDetectorRef in the refresh() method just after receiving the new data, inject ChangeDetectorRef in the constructor and use detectChanges like this:

import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
import { LanguageModel, LANGUAGE_DATA } from '../../../../models/language.model';
import { LanguageAddComponent } from './language-add/language-add.component';
import { AuthService } from '../../../../services/auth.service';
import { LanguageDataSource } from './language-data-source';
import { LevelbarComponent } from '../../../../directives/levelbar/levelbar.component';
import { DataSource } from '@angular/cdk/collections';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import { MatSnackBar, MatDialog } from '@angular/material';

@Component({
  selector: 'app-language',
  templateUrl: './language.component.html',
  styleUrls: ['./language.component.scss']
})
export class LanguageComponent implements OnInit {
  displayedColumns = ['name', 'native', 'code', 'level'];
  teachDS: any;

  user: any;

  constructor(private authService: AuthService, private dialog: MatDialog,
              private changeDetectorRefs: ChangeDetectorRef) { }

  ngOnInit() {
    this.refresh();
  }

  add() {
    this.dialog.open(LanguageAddComponent, {
      data: { user: this.user },
    }).afterClosed().subscribe(result => {
      this.refresh();
    });
  }

  refresh() {
    this.authService.getAuthenticatedUser().subscribe((res) => {
      this.user = res;
      this.teachDS = new LanguageDataSource(this.user.profile.languages.teach);
      this.changeDetectorRefs.detectChanges();
    });
  }
}

4 Comments

That seems to work, is this the proper way to do it? Seems a bit hacky...
What are the other ways? Could you provide examples in your solution for a complete answer?
this made my who matTable become unresponsive. Must have done something wrong.
74

So for me, nobody gave the good answer to the problem that i met which is almost the same than @Kay. For me it's about sorting, sorting table does not occur changes in the mat. I purpose this answer since it's the only topic that i find by searching google. I'm using Angular 6.

As said here:

Since the table optimizes for performance, it will not automatically check for changes to the data array. Instead, when objects are added, removed, or moved on the data array, you can trigger an update to the table's rendered rows by calling its renderRows() method.

So you just have to call renderRows() in your refresh() method to make your changes appears.

See here for integration.

4 Comments

If the table data source is altered on the client, this answer is what you are probably looking for. Works great!
This is the correct answer as of angular material 8
Thank you. But from which object should I call the "renderRows()"? Is it in 'this.datasource'?
@WitnessTruth add a @ViewChild(MatTable) table: MatTable<any>; and call this.table.renderRows()
44

In Angular 9, the secret is this.dataSource.data = this.dataSource.data;

Example:

import { MatTableDataSource } from '@angular/material/table';

dataSource: MatTableDataSource<MyObject>;

refresh(): void {
    this.applySomeModif();
    // Do what you want with dataSource

    this.dataSource.data = this.dataSource.data;
}

applySomeModif(): void {
    // add some data
    this.dataSource.data.push(new MyObject());
    // delete index number 4
    this.dataSource.data.splice(4, 0);
}

5 Comments

THAT IS JUST SUPPER WEIRD, shame on Angular material!
@Arash I agree with you :/ but I prefer this solution instead of the proper one with hundreds lines...
Underrated answer. Thanks @Nicolas, I had been scratching my head for the past 24 hours as one table was rendering properly, while another one wasn't.
Not even this was working for me. The only thing that worked was this.dataSource.data = this.dataSource.data.filter(a => a);
This saved me. Thank you so much. Worked on Angular 17 and AngularMaterial 17.3 . I don't know why and how it worked but my problem is fixed.
36

Since you are using MatPaginator, you just need to do any change to paginator, this triggers data reload.

Simple trick:

this.paginator._changePageSize(this.paginator.pageSize); 

This updates the page size to the current page size, so basically nothing changes, except the private _emitPageEvent() function is called too, triggeing table reload.

4 Comments

I tried your code and it does not work (has no effect). However nextPage and then previousPage again works, but is no solution.
_changePageSize() isn't public right? Is it safe to use? More on stackoverflow.com/questions/59093781/…
this.table.renderRows(); didn't work, but your answer worked perfectly. Feels a bit hacky but does what it needs to do!
@Jones - _changePageSize() is implicitly public (since there's no access modifier specified). But this seems intentional, since there are other properties in _MatPaginatorBase which are private.
15

After adding a new data row, I refreshed my material table by updating dataSource without using its instance.

Table in HTML:

<table mat-table #table [dataSource]="myDataArray">

addUser() in file component.ts:

public USER_DATA: user[] = [];

public newUser = {userName: "ABC", email: "[email protected]"};
public myDataArray: any;


addUser() {
    const newUsersArray = this.USER_DATA;
    newUsersArray.push(this.newUser);
    this.myDataArray = [...newUsersArray]; // Refresh the dataSource
}

2 Comments

Saved my Friday eve. Yep, seems using spread operator refreshes the property value.
This is the correct and easier way, please mark this as answered @hdjemai
13

You can also use the renderRows() method:

@ViewChild(MatTable, {static: false}) table : MatTable<any>  // Initialize

then

this.table.renderRows();

For reference, check this out: Angular 10|9|8 Edit/ Add/ Delete Rows in Material Table with using Dialogs inline Row Operation

3 Comments

thanks a lot.. was looking exactly for that, for my case i change the datasource manually and i just want to re-render the rows.. so voila!
You are using #mytable in the template but I don't see how you are using it in the component. What am I missing?
He's referring to the table via its class not its name, if that's what you were looking for.
12

You can just use the datasource connect function

this.datasource.connect().next(data);

like so. 'data' being the new values for the datatable

1 Comment

Had potential but doesn't seem to work. If after that you access this.datasource.data, Its not updated.
12
this.dataSource = new MatTableDataSource<Element>(this.elements);

Add this line below your action of add or delete the particular row.

refresh() {
  this.authService.getAuthenticatedUser().subscribe((res) => {
    this.user = new MatTableDataSource<Element>(res);   
  });
}

3 Comments

what is this.elements
Will this break sort?
Yes it breaks sorting.
12

Well, I ran into a similar problem where I added something to the data source, and it's not reloading.

The easiest way I found was simply to reassign the data:

let dataSource = ['a','b','c']
dataSource.push('d')
let cloned = dataSource.slice()
// Or in ECMAScript 2015 (ES6): // let cloned = [...dataSource]
dataSource = cloned

Comments

9

Best way to do this is by adding an additional observable to your Datasource implementation.

In the connect method you should already be using Observable.merge to subscribe to an array of observables that include the paginator.page, sort.sortChange, etc. You can add a new subject to this and call next on it when you need to cause a refresh.

something like this:

export class LanguageDataSource extends DataSource<any> {

    recordChange$ = new Subject();

    constructor(private languages) {
      super();
    }

    connect(): Observable<any> {

      const changes = [
        this.recordChange$
      ];

      return Observable.merge(...changes)
        .switchMap(() => return Observable.of(this.languages));
    }

    disconnect() {
      // No-op
    }
}

And then you can call recordChange$.next() to initiate a refresh.

Naturally I would wrap the call in a refresh() method and call it off of the datasource instance w/in the component, and other proper techniques.

4 Comments

This method may the right way. It's works fine for me
how do i implement this when i want to extend MatTableDataSource? When i try your code example i get the error Property 'connect' in type 'customDataSource<T>' is not assignable to the same property in base type 'MatTableDataSource<T>'. Type '() => Observable<any>' is not assignable to type '() => BehaviorSubject<T[]>'. Type 'Observable<any>' is not assignable to type 'BehaviorSubject<T[]>'. Property '_value' is missing in type 'Observable<any>'.
@Maurice the type MatTableDataSource implements the connect method with a different return type. It uses BehaviorSubject<t[]> which means you just need to alter example to return this instead of an Observable. You should still be able to use DataSource but if you have to use MatTableDataSource then return a BehaviorSubject that is subscribed to your observable, assuming you have one to start from. Hope that helps. You can refer to the source for MatTableDataSource for exact syntax of new datasource type: github.com/angular/material2/blob/master/src/lib/table/…
The link to the data table component source is broken. This link should work: github.com/angular/components/blob/main/src/material/table/…
7

There are two ways to do it, because Angular Material is inconsistent, and this is very poorly documented. Angular material table won't update when a new row will arrive. Surprisingly, it is told it is because of performance issues. But it looks more like a by-design issue, and they can not change it. It should be expected for the table to update when a new row occurs. If this behavior should not be enabled by default, there should be a switch to switch it off.

Anyway, we can not change Angular Material. But we can basically use a very poorly documented method to do it:

One - if you use an array directly as a source:

call table.renderRows()

where table is ViewChild of the mat-table

Second - if you use sorting and other features

table.renderRows() surprisingly won't work. Because mat-table is inconsistent here. You need to use a hack to tell the source changed. You do it with this method:

this.dataSource.data = yourDataSource;

where dataSource is MatTableDataSource wrapper used for sorting and other features.

Comments

6

I achieved a good solution using two resources:

refreshing both dataSource and paginator:

this.dataSource.data = this.users;
this.dataSource.connect().next(this.users);
this.paginator._changePageSize(this.paginator.pageSize);

where for example dataSource is defined here:

    users: User[];
    ...
    dataSource = new MatTableDataSource(this.users);
    ...
    this.dataSource.paginator = this.paginator;
    ...

Comments

6

I have tried some of the previous suggestions. It does update the table, but I have some concerns:

  1. Updating dataSource.data with its clone. e.g.

    this.dataSource.data = [...this.dataSource.data];
    

    If the data is large, this will reallocate lot of memory. Moreover, MatTable thinks that everything is new inside the table, so it may cause performance issue. I found my table flickers where my table has about 300 rows.

  2. Calling paginator._changePageSize. e.g.

    this.paginator._changePageSize(this.paginator.pageSize);
    

    It will emit page event. If you have already had some handling for the page event. You may find it weird because the event may be fired more than once. And there can be a risk that if somehow the event will trigger _changePageSize() indirectly, it will cause infinite loop...

    I suggest another solution here. If your table is not relying on dataSource's filter field.

  3. You may update the filter field to trigger table refresh:

    this.dataSource.filter = ' '; // Note that it is a space, not empty string
    

    By doing so, the table will perform filtering and thus updating the UI of the table. But it requires having your own dataSource.filterPredicate() to handling your filtering logic.

Comments

5

I had tried ChangeDetectorRef, Subject and BehaviourSubject, but this works for me:

dataSource = [];
this.dataSource = [];
setTimeout(() => {
  this.dataSource = this.tableData[data];
}, 200)

1 Comment

what's going on here? I feel like variable naming mistakes were made.
4

You can easily update the data of the table using "concat":

for example:

language.component.ts

teachDS: any[] = [];

language.component.html

<table mat-table [dataSource]="teachDS" class="list">

And, when you update the data (language.component.ts):

addItem() {
    // newItem is the object added to the list using a form or other way
    this.teachDS = this.teachDS.concat([newItem]);
 }

When you're using "concat" angular detect the changes of the object (this.teachDS) and you don't need to use another thing.

PD: It's work for me in angular 6 and 7, I didn't try another version.

2 Comments

Yes, It works for me, is a problem about the reference and value var, the change detection doesn't see the new changes, for that you need update it.
This might work if the dataSource is just an array but not when dataSource is a MatTableDataSource object.
4

In Angular 10, this is what works for me:

In the HTML:

<mat-table [dataSource]="myArray">

In the TypeScript component:

myArray: MyObject[] = [];

addObjectToTable(object:MyObject): void {
    // To prevent duplicated objects

    if (object&& !this.myArray.includes(object)) {
        this.myArray.push(object);

        // To force the data table's datasource to refresh
        this.myArray= [...this.myArray];
    }
 }

1 Comment

I'm not sure if this is the best solution but this worked for me. If there any other better solutions please suggest.
2

This worked for me:

refreshTableSorce() {
    this.dataSource = new MatTableDataSource<Element>(this.newSource);
}

1 Comment

Not an ideal solution as it recreates source for the table.And using this with streamlined/ socket is not an efficient.
1
import { Subject } from 'rxjs/Subject';
import { Observable } from 'rxjs/Observable';

export class LanguageComponent implemnts OnInit {
  displayedColumns = ['name', 'native', 'code', 'leavel'];
  user: any;
  private update = new Subject<void>();
  update$ = this.update.asObservable();

  constructor(private authService: AuthService, private dialog: MatDialog) {}

   ngOnInit() {
     this.update$.subscribe(() => { this.refresh()});
   }

   setUpdate() {
     this.update.next();
   }

   add() {
     this.dialog.open(LanguageAddComponent, {
     data: { user: this.user },
   }).afterClosed().subscribe(result => {
     this.setUpdate();
   });
 }

 refresh() {
   this.authService.getAuthenticatedUser().subscribe((res) => {
     this.user = res;
     this.teachDS = new LanguageDataSource(this.user.profile.languages.teach);   
    });
  }
}

1 Comment

Please add an explanation to your answer, just posting code is not very helpful and can result in your answer being removed.
1

in my case (Angular 6+), I inherited from MatTableDataSource to create MyDataSource. Without calling after this.data = someArray

this.entitiesSubject.next(this.data as T[])

data where not displayed

class MyDataSource

export class MyDataSource<T extends WhateverYouWant> extends MatTableDataSource<T> {

    private entitiesSubject = new BehaviorSubject<T[]>([]);


    loadDataSourceData(someArray: T[]){
        this.data = someArray //whenever it comes from an API asyncronously or not
        this.entitiesSubject.next(this.data as T[])// Otherwise data not displayed
    }

    public connect(): BehaviorSubject<T[]> {
        return this.entitiesSubject
    }

}//end Class 

Comments

0

I think the MatTableDataSource object is some way linked with the data array that you pass to MatTableDataSource constructor.

For instance:

dataTable: string[];
tableDS: MatTableDataSource<string>;

ngOnInit(){
   // here your pass dataTable to the dataSource
   this.tableDS = new MatTableDataSource(this.dataTable); 
}

So, when you have to change data; change on the original list dataTable and then reflect the change on the table by call _updateChangeSubscription() method on tableDS.

For instance:

this.dataTable.push('testing');
this.tableDS._updateChangeSubscription();

That's work with me through Angular 6.

1 Comment

That method is prefixed with an underscore _ and you call it ?
0

This is working for me:

dataSource = new MatTableDataSource<Dict>([]);
    public search() {
        let url = `${Constants.API.COMMON}/dicts?page=${this.page.number}&` + 
        (this.name == '' ? '' : `name_like=${this.name}`);
    this._http.get<Dict>(url).subscribe((data)=> {
    // this.dataSource = data['_embedded'].dicts;
    this.dataSource.data =  data['_embedded'].dicts;
    this.page = data['page'];
    this.resetSelection();
  });
}

So you should declare your datasource instance as MatTableDataSource

Comments

0

I did some more research and found this place to give me what I needed - feels clean and relates to update data when refreshed from server: https://blog.angular-university.io/angular-material-data-table/

Most credits to the page above. Below is a sample of how a mat-selector can be used to update a mat-table bound to a datasource on change of selection. I am using Angular 7. Sorry for being extensive, trying to be complete but concise - I have ripped out as many non-needed parts as possible. With this hoping to help someone else getting forward faster!

organization.model.ts:

export class Organization {
    id: number;
    name: String;
}

organization.service.ts:

import { Observable, empty } from 'rxjs';
import { of } from 'rxjs';

import { Organization } from './organization.model';

export class OrganizationService {
  getConstantOrganizations(filter: String): Observable<Organization[]> {
    if (filter === "All") {
      let Organizations: Organization[] = [
        { id: 1234, name: 'Some data' }
      ];
      return of(Organizations);
     } else {
       let Organizations: Organization[] = [
         { id: 5678, name: 'Some other data' }
       ];
     return of(Organizations);
  }

  // ...just a sample, other filterings would go here - and of course data instead fetched from server.
}

organizationdatasource.model.ts:

import { CollectionViewer, DataSource } from '@angular/cdk/collections';
import { Observable, BehaviorSubject, of } from 'rxjs';
import { catchError, finalize } from "rxjs/operators";

import { OrganizationService } from './organization.service';
import { Organization } from './organization.model';

export class OrganizationDataSource extends DataSource<Organization> {
  private organizationsSubject = new BehaviorSubject<Organization[]>([]);

  private loadingSubject = new BehaviorSubject<boolean>(false);

  public loading$ = this.loadingSubject.asObservable();

  constructor(private organizationService: OrganizationService, ) {
    super();
  }

  loadOrganizations(filter: String) {
    this.loadingSubject.next(true);

    return this.organizationService.getOrganizations(filter).pipe(
      catchError(() => of([])),
      finalize(() => this.loadingSubject.next(false))
    ).subscribe(organization => this.organizationsSubject.next(organization));
  }

  connect(collectionViewer: CollectionViewer): Observable<Organization[]> {
    return this.organizationsSubject.asObservable();
  }

  disconnect(collectionViewer: CollectionViewer): void {
    this.organizationsSubject.complete();
    this.loadingSubject.complete();
  }
}

organizations.component.html:

<div class="spinner-container" *ngIf="organizationDataSource.loading$ | async">
    <mat-spinner></mat-spinner>
</div>

<div>
  <form [formGroup]="formGroup">
    <mat-form-field fxAuto>
      <div fxLayout="row">
        <mat-select formControlName="organizationSelectionControl" (selectionChange)="updateOrganizationSelection()">
          <mat-option *ngFor="let organizationSelectionAlternative of organizationSelectionAlternatives"
            [value]="organizationSelectionAlternative">
            {{organizationSelectionAlternative.name}}
          </mat-option>
        </mat-select>
      </div>
    </mat-form-field>
  </form>
</div>

<mat-table fxLayout="column" [dataSource]="organizationDataSource">
  <ng-container matColumnDef="name">
    <mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
    <mat-cell *matCellDef="let organization">{{organization.name}}</mat-cell>
  </ng-container>

  <ng-container matColumnDef="number">
    <mat-header-cell *matHeaderCellDef>Number</mat-header-cell>
    <mat-cell *matCellDef="let organization">{{organization.number}}</mat-cell>
  </ng-container>

  <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
  <mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>

organizations.component.scss:

.spinner-container {
    height: 360px;
    width: 390px;
    position: fixed;
}

organization.component.ts:

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';
import { Observable } from 'rxjs';

import { OrganizationService } from './organization.service';
import { Organization } from './organization.model';
import { OrganizationDataSource } from './organizationdatasource.model';

@Component({
  selector: 'organizations',
  templateUrl: './organizations.component.html',
  styleUrls: ['./organizations.component.scss']
})
export class OrganizationsComponent implements OnInit {
  public displayedColumns: string[];
  public organizationDataSource: OrganizationDataSource;
  public formGroup: FormGroup;

  public organizationSelectionAlternatives = [{
    id: 1,
    name: 'All'
  }, {
    id: 2,
    name: 'With organization update requests'
  }, {
    id: 3,
    name: 'With contact update requests'
  }, {
    id: 4,
    name: 'With order requests'
  }]

  constructor(
    private formBuilder: FormBuilder,
    private organizationService: OrganizationService) { }

  ngOnInit() {
    this.formGroup = this.formBuilder.group({
      'organizationSelectionControl': []
    })

    const toSelect = this.organizationSelectionAlternatives.find(c => c.id == 1);
    this.formGroup.get('organizationSelectionControl').setValue(toSelect);

    this.organizationDataSource = new OrganizationDataSource(this.organizationService);
    this.displayedColumns = ['name', 'number' ];
    this.updateOrganizationSelection();
  }

  updateOrganizationSelection() {
    this.organizationDataSource.loadOrganizations(this.formGroup.get('organizationSelectionControl').value.name);
  }
}

Comments

0

After reading Material Table not updating post data update #11638 Bug Report I found the best (read, the easiest solution) was as suggested by the final commentor 'shhdharmen' with a suggestion to use an EventEmitter.

This involves a few simple changes to the generated datasource class

ie) add a new private variable to your datasource class

import { EventEmitter } from '@angular/core';
...
private tableDataUpdated = new EventEmitter<any>();

and where I push new data to the internal array (this.data), I emit an event.

public addRow(row:myRowInterface) {
    this.data.push(row);
    this.tableDataUpdated.emit();
}

and finally, change the 'dataMutation' array in the 'connect' method - as follows

const dataMutations = [
    this.tableDataUpdated,
    this.paginator.page,
    this.sort.sortChange
];

Comments

0
// this is the dataSource    
this.guests = [];

this.guests.push({id: 1, name: 'Ricardo'});

// refresh the dataSource
this.guests = Array.from(this.guest);

Comments

0

In Angular 15, none of the previous solutions worked for me.

Instead, I had to use

 @ViewChild(MatTable) table!: MatTable<MyStruct>;
 ...
 this.table.renderRows();

See the StackBlitz example for an example.

Comments

0

When you set up your datasource.ts file instead of using a simple array for data, use a subject and getter/setter for data like so:

 dataStream = new BehaviorSubject<DataSourceItem[]>(EXAMPLE_DATA);
 set data(v: DataSourceItem[]) { this.dataStream.next(v); }
 get data(): DataSourceItem[] { return this.dataStream.value; }

Then in your connect() function use the dataStream subject like so:

return merge(this.dataStream, this.paginator.page, this.sort.sortChange)

So now when you change your dataSource.data array...like so:

this.dataSource.data = ['my','new','item']

it will trigger the this.dataStream.next(v) in the setter and the connect() function will update your table properly.

A full working example can be found here: https://stackblitz.com/edit/angular-material2-issue-yzhsml?file=app%2Fdata-table-datasource.ts

Comments

0

Try this. It may help you.

Start with a function which loads users.

loadUser() {
    this.userService.getListOfUsers().subscribe()
        (response: any) => {
            this.dataSource = response
            this.dataSource.paginator = this.paginator;
        }

}

The define a refresh function, which will be used to refresh the table after deleting the user.

refresh() {
    this.loadUser();
    this.dataSource.data = [...this.dataSource.data];
    this.dataSource.paginator = this.paginator;
}

Now you can call the refresh() function after you finish deleting the user process, like below.

deleteUser() {
    ......
    this.refresh()
}

1 Comment

This is working, but those lines in refresh() with the dataSource are not needed. As loadUser() is not synchronous and would set its data later than it would return the execution to refresh(), you would set the dataSource in refresh() with your current data again. Then, somewhat later, when userService delivers, it's setting the data correctly.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.