Angular + Material - Cómo Actualizar Una Fuente De Datos (mat-table)
Estoy usando una mat-table para listar el contenido de los idiomas elegidos por los usuarios. También pueden agregar nuevos idiomas usando el panel de diálogo. Después agregaron un idioma y regresaron. Quiero que mi fuente de datos se actualice para mostrar los cambios realizados.
Inicializo el almacén de datos obteniendo datos de usuario de un servicio y pasándolos a una fuente de datos en la actualización método.
Lenguaje.componente.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);
});
}
}
Idioma-fuente de datos.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
}
}
Así que he intentado llamar a un método de actualización donde obtengo el usuario del backend de nuevo y luego reinicializo la fuente de datos. Sin embargo, esto no funciona, no se están produciendo cambios.
6 answers
Activa una detección de cambio usando ChangeDetectorRef
en el método refresh()
justo después de recibir los nuevos datos, inyecte ChangeDetectorRef en el constructor y use DetectChanges así:
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();
});
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-16 17:37:34
No se si el ChangeDetectorRef
fue requerido cuando la pregunta fue creada, pero ahora esto es suficiente:
import { MatTableDataSource } from '@angular/material/table';
// ...
dataSource = new MatTableDataSource<MyDataType>();
refresh() {
this.myService.doSomething().subscribe(data: MyDataType[] => {
this.dataSource.data = data;
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-12 08:57:17
Ya que está utilizando MatPaginator
, solo necesita hacer cualquier cambio en paginator, esto desencadena la recarga de datos.
Truco simple:
this.paginator._changePageSize(this.paginator.pageSize);
Esto actualiza el tamaño de página al tamaño de página actual, por lo que básicamente nada cambia, excepto que también se llama a la función privada _emitPageEvent()
, activando la recarga de tabla.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-22 15:56:54
La mejor manera de hacerlo es agregando un observable adicional a su implementación de fuente de datos.
En el método connect ya debería estar usando Observable.merge
para suscribirse a una matriz de observables que incluyen el paginador.page, sort.sortChange, etc. Puede agregar un nuevo sujeto a esto y llamar a next cuando necesite causar una actualización.
Algo como esto:
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
}
}
Y luego puedes llamar a recordChange$.next()
para iniciar una actualización.
Naturalmente me gustaría envolver la llamada en un método refresh () y lo llama fuera de la instancia de datasource w/en el componente, y otras técnicas adecuadas.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-03 12:37:37
Esto.DataSource = new MatTableDataSource (this.elementos);
Agregue esta línea debajo de su acción de agregar o eliminar la fila en particular.
refresh() {
this.authService.getAuthenticatedUser().subscribe((res) => {
this.user = new MatTableDataSource<Element>(res);
});
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-25 13:33:14
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);
});
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-05 15:05:11