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.
It's trying to sort by element['project.name']. Obviously element doesn't have such a property.
It should be easy to create a custom datasource that extends MatTableDatasource and supports sorting by nested object properties. Check out the examples in material.angular.io docs on using a custom source.
I had the same issue, by testing the first proposition I had some errors, I could fixe it by adding "switch (property)"
this.dataSource.sortingDataAccessor =(item, property) => {
switch (property) {
case 'project.name': return item.project.name;
default: return item[property];
}
};
I like @Hieu_Nguyen solutions. I'll just add that if you use lodash in you project as I do then the solution translates to this:
import * as _ from 'lodash';
this.dataSource.sortingDataAccessor = _.get;
No need to reinvent the deep property access.
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;
}
Just add this to your data source and you will be able to access the nested object
this.dataSource.sortingDataAccessor = (item, property) => {
// Split '.' to allow accessing property of nested object
if (property.includes('.')) {
const accessor = property.split('.');
let value: any = item;
accessor.forEach((a) => {
value = value[a];
});
return value;
}
// Access as normal
return item[property];
};
I use a generic method which allows you to use a dot.seperated.path with mat-sort-header
or matColumnDef
. This fails silently returning undefined if it cannot find the property dictated by the path.
function pathDataAccessor(item: any, path: string): any {
return path.split('.')
.reduce((accumulator: any, key: string) => {
return accumulator ? accumulator[key] : undefined;
}, item);
}
You just need to set the data accessor
this.dataSource.sortingDataAccessor = pathDataAccessor;