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