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.
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:
So you just have to call renderRows() in your refresh() method to make your changes appears.
See here for integration.
// this is the dataSource
this.guests = [];
this.guests.push({id: 1, name: 'Ricardo'});
// refresh the dataSource this.guests = Array.from(this.guest);
Trigger a change detection by using
ChangeDetectorRef
in therefresh()
method just after receiving the new data, inject ChangeDetectorRef in the constructor and use detectChanges like this:You can easily update the data of the table using "concat":
for example:
language.component.ts
language.component.html
And, when you update the data (language.component.ts):
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.
I released a library aimed to be the official Material DataSource in the future, supporting any kind of input streams (sort, pagination, filters), and some configuration with debugging to see how it works while you're coding.
You can find the StackBlitz demo and further information here:
https://medium.com/@matheo/reactive-datasource-for-angular-1d869b0155f6
I'd be glad to hear your opinion and support your use cases if necessary.
Happy coding!
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:
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.