182 votes

Angular + Material - Comment rafraîchir une source de données (mat-table)

J'utilise un tapis-table pour lister le contenu des langues choisies par les utilisateurs. Ils peuvent également ajouter de nouvelles langues en utilisant le panneau de dialogue. Après avoir ajouté une langue et être revenu. Je veux que ma source de données soit rafraîchie pour montrer les changements qu'ils ont faits.

J'initialise le datastore en récupérant les données de l'utilisateur depuis un service et en les passant dans une source de données dans la méthode de rafraîchissement.

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);   
    });
  }
}

langue-données-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
  }

}

J'ai donc essayé d'appeler une méthode de rafraîchissement où je récupère à nouveau l'utilisateur depuis le backend, puis je réinitialise la source de données. Cependant, cela ne fonctionne pas, aucun changement ne se produit.

1 votes

Si vous souhaitez déclencher le changement "à partir de la source de données", veuillez consulter le site suivant stackoverflow.com/questions/47897694/

0 votes

Les émetteurs d'événements peuvent être utilisés dans ce cas. stackoverflow.com/a/44858648/8300620

130voto

MA-Maddin Points 3242

Je ne sais pas si le ChangeDetectorRef était nécessaire lorsque la question a été créée, mais cela suffit désormais :

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

// ...

dataSource = new MatTableDataSource<MyDataType>();

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

Exemple :
StackBlitz

6 votes

Bien que cette solution fonctionne, elle perturbe le paginateur matériel si l'élément est ajouté ailleurs que sur la première page de résultats. Je comprends que cela dépasse le cadre de cette question, mais comme les deux sont liés, auriez-vous une solution rapide à ce problème que vous pourriez ajouter à votre réponse ?

6 votes

@Knight Je pense que vous devez affecter le Paginator à la section MatTableDataSource.paginator après que la vue du Paginator ait été initialisée. Voir la description de paginator la propriété ici : material.angular.io/components/table/api#MatTableDataSource

0 votes

Bonne référence. Je ne l'avais pas encore repérée dans la documentation. Merci.

78voto

HDJEMAI Points 4396

Déclenchez une détection de changement en utilisant ChangeDetectorRef dans le refresh() méthode juste après avoir reçu les nouvelles données, injecter ChangeDetectorRef dans le constructeur et utiliser detectChanges comme ça :

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();
    });
  }
}

17 votes

Cela semble fonctionner, est-ce la bonne façon de procéder ? Cela semble un peu compliqué...

1 votes

Quels sont les autres moyens ? Pourriez-vous fournir des exemples dans votre solution pour une réponse complète ?

61voto

4x10m Points 272

Donc pour moi, personne n'a donné la bonne réponse au problème que j'ai rencontré qui est presque le même que @Kay. Pour moi, il s'agit de trier, le tri de la table n'entraîne pas de changements dans la matrice. Je cherche cette réponse car c'est le seul sujet que j'ai trouvé en cherchant sur Google. J'utilise Angular 6.

Comme dit ici :

Comme la table optimise les performances, elle ne vérifie pas automatiquement les modifications apportées au tableau de données. En revanche, lorsque des objets sont ajoutés, supprimés ou déplacés dans le tableau de données, vous pouvez déclencher une mise à jour des lignes rendues du tableau en appelant la méthode renderRows().

Donc vous devez juste appeler renderRows() dans votre rafraîchir() pour effectuer vos modifications apparaît.

Voir ici pour l'intégration.

1 votes

Si la source de données de la table est modifiée sur le client, cette réponse est probablement celle que vous recherchez. Cela fonctionne très bien !

0 votes

C'est la réponse correcte à partir du matériau angulaire 8.

0 votes

Merci. Mais à partir de quel objet dois-je appeler la fonction "renderRows()" ? Est-ce dans 'this.datasource' ?

32voto

takeshin Points 16579

Puisque vous utilisez MatPaginator il suffit de modifier le paginateur pour que les données soient rechargées.

Un truc simple :

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

Cela met à jour la taille de la page en fonction de la taille actuelle de la page, de sorte que rien ne change, à l'exception de la propriété privée de la page. _emitPageEvent() est également appelée, ce qui déclenche le rechargement de la table.

0 votes

J'ai essayé votre code et il ne fonctionne pas (n'a aucun effet). Par contre nextPage puis previousPage fonctionne à nouveau, mais ce n'est pas une solution.

1 votes

_changePageSize() n'est pas public, n'est-ce pas ? Peut-on l'utiliser en toute sécurité ? Plus sur stackoverflow.com/questions/59093781/

0 votes

Ça a marché pour moi, merci beaucoup !

11voto

Pooja Paigude Points 71
this.dataSource = new MatTableDataSource<Element>(this.elements);

Ajoutez cette ligne en dessous de votre action d'ajout ou de suppression d'une ligne particulière.

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

0 votes

Qu'est-ce que c'est ?

0 votes

Est-ce que ça va casser le tri ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X