web-dev-qa-db-fra.com

Angular Material 2 DataTable Trier avec des objets imbriqués

J'ai un DataTable Angular Material 2 normal avec des en-têtes de tri . Tous les types d'en-tête fonctionnent bien. Sauf pour celui avec un objet comme valeur . Ceux-ci ne trient pas du tout. 

Par exemple:

 <!-- Project Column - This should sort!-->
    <ng-container matColumnDef="project.name">
      <mat-header-cell *matHeaderCellDef mat-sort-header> Project Name </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.project.name}} </mat-cell>
    </ng-container>

notez le element.project.name

Voici la configuration displayColumn:

 displayedColumns = ['project.name', 'position', 'name', 'test', 'symbol'];

Changer 'project.name' en 'project' ne fonctionne pas, ni "project['name']"

Qu'est-ce que je rate? Est-ce seulement possible?

Voici un Stackblitz: Angular Material2 Objets de tri DataTable

Edit: Merci pour toutes vos réponses . Je l'ai déjà utilisé avec des données dynamiques. Je n'ai donc pas besoin d'ajouter une instruction switch pour chaque nouvelle propriété imbriquée.

Voici ma solution: (La création d'un nouveau DataSource qui étend MatTableDataSource n'est pas nécessaire)

export class NestedObjectsDataSource extends MatTableDataSource<MyObjectType> {

  sortingDataAccessor: ((data: WorkingHours, sortHeaderId: string) => string | number) =
    (data: WorkingHours, sortHeaderId: string): string | number => {
      let value = null;
      if (sortHeaderId.indexOf('.') !== -1) {
        const ids = sortHeaderId.split('.');
        value = data[ids[0]][ids[1]];
      } else {
        value = data[sortHeaderId];
      }
      return _isNumberValue(value) ? Number(value) : value;
    }

  constructor() {
    super();
  }
}
25
Lados

Il était difficile de trouver de la documentation à ce sujet, mais cela est possible en utilisant sortingDataAccessor et une instruction switch. Par exemple:

@ViewChild(MatSort) sort: MatSort;

ngOnInit() {
  this.dataSource = new MatTableDataSource(yourData);
  this.dataSource.sortingDataAccessor = (item, property) => {
    switch(property) {
      case 'project.name': return item.project.name;
      default: return item[property];
    }
  };
  this.dataSource.sort = sort;
}
49
Steve Sanders

Vous pouvez écrire une fonction dans le composant pour obtenir les propriétés de l'objet. Puis utilisez-le dans dataSource.sortingDataAccessor comme ci-dessous

getProperty = (obj, path) => (
  path.split('.').reduce((o, p) => o && o[p], obj)
)

ngOnInit() {
  this.dataSource = new MatTableDataSource(yourData);
  this.dataSource.sortingDataAccessor = (obj, property) => this.getProperty(obj, property);
  this.dataSource.sort = sort;
}

columnDefs = [
  {name: 'project.name', title: 'Project Name'},
  {name: 'position', title: 'Position'},
  {name: 'name', title: 'Name'},
  {name: 'test', title: 'Test'},
  {name: 'symbol', title: 'Symbol'}
];

Et en html

<ng-container *ngFor="let col of columnDefs" [matColumnDef]="col.name">
      <mat-header-cell *matHeaderCellDef>{{ col.title }}</mat-header-cell>
      <mat-cell *matCellDef="let row">
        {{ getProperty(row, col.name) }}
      </mat-cell>
  </ng-container>
15
Hieu Nguyen

La réponse donnée peut même être abrégée, aucun changement requis, tant que vous utilisez la notation par points pour les champs.

ngOnInit() {
  this.dataSource = new MatTableDataSource(yourData);

  this.dataSource.sortingDataAccessor = (item, property) => {
     if (property.includes('.')) return property.split('.').reduce((o,i)=>o[i], item)
     return item[property];
  };

  this.dataSource.sort = sort;
}
3
Erik Schaareman

J'ai personnalisé pour plusieurs niveaux d'objet imbriqués.

this.dataSource.sortingDataAccessor =
  (data: any, sortHeaderId: string): string | number => {
    let value = null;
    if (sortHeaderId.includes('.')) {
      const ids = sortHeaderId.split('.');
      value = data;
      ids.forEach(function (x) {
        value = value? value[x]: null;
      });
    } else {
      value = data[sortHeaderId];
    }
    return _isNumberValue(value) ? Number(value) : value;
  };
1
E.Sarawut

J'utilise une méthode générique qui vous permet d'utiliser un dot.seperated.path avec mat-sort-header ou matColumnDef. Cela échoue en renvoyant silencieusement indéfini s'il ne peut pas trouver la propriété dictée par le chemin.

function pathDataAccessor(item: any, path: string): any {
  return path.split('.')
    .reduce((accumulator: any, key: string) => {
      return accumulator ? accumulator[key] : undefined;
    }, item);
}

Il vous suffit de définir l’accesseur de données 

this.dataSource.sortingDataAccessor = pathDataAccessor;
0
Toby Harris

Il essaie de trier par élément ['project.name']. De toute évidence, l'élément n'a pas une telle propriété.

Il devrait être facile de créer une source de données personnalisée qui étend MatTableDatasource et prend en charge le tri par propriétés d'objet imbriquées. Découvrez les exemples dans la documentation material.angular.io sur l'utilisation d'une source personnalisée.

0
funkizer