Angular Material 2 DataTable使用嵌套对象进行排序

Lad*_*dos 54 angular-material2 angular

我有一个带有排序标题的普通Angular Material 2 DataTable.所有排序都是标题工作正常.除了具有对象作为值的那个.这些根本不排序.

例如:

 <!-- 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>
Run Code Online (Sandbox Code Playgroud)

请注意 element.project.name

这是displayColumn配置:

 displayedColumns = ['project.name', 'position', 'name', 'test', 'symbol'];
Run Code Online (Sandbox Code Playgroud)

更改'project.name''project'不工作,也不"project['name']"

我错过了什么?这甚至可能吗?

这是Stackblitz: Angular Material2 DataTable排序对象

编辑: 谢谢你的所有答案.我已经使用动态数据了.所以我不必为每个新的嵌套属性添加switch语句.

这是我的解决方案:(创建一个扩展MatTableDataSource的新DataSource不是必需的)

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();
  }
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*ers 106

很难找到关于此的文档,但可以通过使用sortingDataAccessor和switch语句来实现.例如:

@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;
}
Run Code Online (Sandbox Code Playgroud)

  • 你救了我.谢谢. (6认同)
  • 我必须将其放置在ngAfterViewInit中才能正常工作 (2认同)

小智 19

您可以在组件中编写函数以从对象获取深层属性.然后在dataSource.sortingDataAccessor下面使用它

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'}
];
Run Code Online (Sandbox Code Playgroud)

并在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>
Run Code Online (Sandbox Code Playgroud)

  • 我也喜欢这个解决方案。我在我的项目中使用了 `lodash`,所以如果你使用 `lodash`,这个解决方案会转化为:`this.dataSource.sortingDataAccessor = _.get;` 无需重新发明深层属性访问。 (3认同)
  • 我想我比我的答案更喜欢这个! (2认同)
  • @andy你应该把它作为一个单独的答案。这在评论中听起来太简单了,不可能是真的。我要做的就是这些吗? (2认同)

And*_*ndy 8

我喜欢@Hieu_Nguyen 解决方案。我将补充一点,如果您像我一样在项目中使用 lodash,那么解决方案将转换为:

import * as _ from 'lodash';

this.dataSource.sortingDataAccessor = _.get; 
Run Code Online (Sandbox Code Playgroud)

无需重新发明深层属性访问。

  • 或者,您可以按原样保留列名称,并通过“mat-sort-header”独立覆盖 sortHeaderId,例如“mat-sort-header =“user.name”” (2认同)

Tob*_*ris 7

我使用了一种通用方法,它允许您使用 dot.seperated.path 和mat-sort-headermatColumnDef。如果找不到路径指定的属性,则此方法将失败,静默返回 undefined。

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

您只需要设置数据访问器

this.dataSource.sortingDataAccessor = pathDataAccessor;
Run Code Online (Sandbox Code Playgroud)

  • 1000% 应该是可接受的解决方案。这是唯一不会为我抛出 typeErrors 的解决方案。 (3认同)

小智 7

只要为字段使用点符号,给出的答案甚至可以缩短,不需要切换。

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;
}
Run Code Online (Sandbox Code Playgroud)