Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular Material 2 DataTable Sorting with nested objects

I have a normal Angular Material 2 DataTable with sort headers. All sort are headers work fine. Except for the one with an object as value. These doesn't sort at all.

For example:

 <!-- 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> 

note the element.project.name

Here's the displayColumn config:

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

Changing 'project.name' to 'project' doesn't work nor "project['name']"

What am I missing? Is this even possible?

Here's a Stackblitz: Angular Material2 DataTable sort objects

Edit: Thanks for all your answers. I've already got it working with dynamic data. So I don't have to add a switch statement for every new nested property.

Here's my solution: (Creating a new DataSource which extends MatTableDataSource is not necessary)

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();   } } 
like image 749
Roman Avatar asked Feb 20 '18 17:02

Roman


2 Answers

It was hard to find documentation on this, but it is possible by using sortingDataAccessor and a switch statement. For example:

@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; } 
like image 139
Steve Sanders Avatar answered Sep 28 '22 02:09

Steve Sanders


You can write a function in component to get deeply property from object. Then use it in dataSource.sortingDataAccessor like below

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'} ]; 

And in 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> 
like image 36
Hieu Nguyen Avatar answered Sep 28 '22 04:09

Hieu Nguyen