带嵌套对象的Angular Material 2数据表排序

带嵌套对象的Angular Material 2数据表排序,angular,angular-material2,Angular,Angular Material2,我有一个带排序标题的普通角度材质2数据表。 所有排序都很好。除了以对象作为值的对象。 这些根本不分类 例如: @ViewChild(MatSort) sort: MatSort; ngOnInit() { this.dataSource = new MatTableDataSource(yourData); this.dataSource.sortingDataAccessor = (item, property) => { switch(property) {

我有一个带排序标题的普通角度材质2数据表。 所有排序都很好。除了以对象作为值的对象。 这些根本不分类

例如:

@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;
}

项目名称
{{element.project.name}
注意
元素.project.name

以下是displayColumn配置:

 displayedColumns = ['project.name', 'position', 'name', 'test', 'symbol'];
'project.name'
更改为
'project'
也不起作用
“project['name']”

我错过了什么?这可能吗

下面是一场闪电战:

编辑: 谢谢你的回答。 我已经让它处理动态数据了。因此,我不必为每个新嵌套属性添加switch语句

以下是我的解决方案:(不需要创建扩展MatTableDataSource的新数据源)

导出类NestedObjectsDataSource扩展MatTableDataSource{
sortingDataAccessor:((数据:工作时间,SortheadeId:string)=>字符串|编号)=
(数据:工作时间,sortHeaderId:string):string | number=>{
设value=null;
if(sortHeaderId.indexOf('.')!=-1){
常量id=sortHeaderId.split('.');
值=数据[ID[0]][ID[1]];
}否则{
值=数据[sortHeaderId];
}
返回_isNumberValue(value)→Number(value):value;
}
构造函数(){
超级();
}
}

它正在尝试按元素['project.name']排序。显然元素没有这样的属性


创建扩展MatTableDatasource并支持按嵌套对象属性排序的自定义数据源应该很容易。查看material.angular.io文档中有关使用自定义源的示例。

很难找到有关此的文档,但可以使用
排序数据访问器和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;
}

我也有同样的问题,通过测试第一个命题,我发现了一些错误,我可以通过添加“switch(property)”来修复它


您可以在组件中编写一个函数来从对象中获取属性。然后在
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'}
];
和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>

{{col.title}}
{{getProperty(行,列名称)}

我为多个嵌套对象级别进行了自定义

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

我使用了一种通用方法,它允许您使用带有
mat sort header
matColumnDef
的dot.separated.path。如果找不到路径指定的属性,则会以静默方式返回undefined失败

function pathDataAccessor(item: any, path: string): any {
  return path.split('.')
    .reduce((accumulator: any, key: string) => {
      return accumulator ? accumulator[key] : undefined;
    }, item);
}
您只需要设置数据访问器

this.dataSource.sortingDataAccessor = pathDataAccessor;

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

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

另一种选择是,没有人在这里扔,先把柱子压平

yourData.map((d) => 
   d.flattenedName = d.project && d.project.name ? 
                     d.project.name : 
                     'Not Specified');

this.dataSource = new MatTableDataSource(yourData);

只是另一种选择,各有利弊

我喜欢@Hieu\u-Nguyen解决方案。我只想补充一点,如果您像我一样在项目中使用lodash,那么解决方案将转化为:

import * as _ from 'lodash';

this.dataSource.sortingDataAccessor = _.get; 

无需重新设计深度属性访问。

使用MatTableDataSource 检查完整的MatSort问题解决方案

在HTML中

    <ng-container matColumnDef="createdDate" @bounceInLeft>
      <th mat-header-cell *matHeaderCellDef mat-sort-header class="date"> Created date
      </th>
          <td mat-cell *matCellDef="let element" class="date"> {{element.createdDate
           | date :'mediumDate'}} </td>
   </ng-container>

  <ng-container matColumnDef="group.name">
    <th mat-header-cell *matHeaderCellDef mat-sort-header class="type"> Group </th>
    <td mat-cell *matCellDef="let element" class="type"> {{element.group.name}} </td>
  </ng-container>

@ViewChild(MatSort, { static: true }) 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;
}

创建日期
{{element.createdDate
|日期:'mediumDate'}
团体
{{element.group.name}
@ViewChild(MatSort,{static:true})sort:MatSort;
恩戈尼尼特(){
this.dataSource=新MatTableDataSource(yourData);
this.dataSource.sortingDataAccessor=(项、属性)=>{
交换机(属性){
案例“project.name”:返回item.project.name;
默认值:返回项[属性];
}
};
this.dataSource.sort=sort;
}

只需将其添加到数据源中,您就可以访问嵌套对象

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

如果您想要有一个具有一些扩展功能的角度材质表,例如嵌套对象的排序,请查看

我创建这个库是因为我缺少了mat table开箱即用的一些功能


高级排序类似于@Hieu-Nguyen建议的答案,但有点扩展,可以按大小写字母进行适当排序。

这似乎是最好的解决方案,小而简洁,而且没有开关那么有限。我真的很喜欢这个实现。减少必须使用/生成的代码。我在上次实现mat表时遇到了问题。在此之前,刷新导致了问题。不过这很干净。我也喜欢这个解决方案。我在我的项目中使用
lodash
,因此如果您使用
lodash
,此解决方案将转换为:
this.dataSource.sortingDataAccessor=\uuu.get无需重新创建深度属性访问。@andy您应该单独回答这个问题。这听起来太简单了,在评论中不可能是真的。。这就是我要做的吗?你救了我。谢谢。您是从
this.dataSource.sort=sort我必须将其放入
ngAfterViewInit
中才能正常工作。如上面的评论所述,只需将其放入ngAfterViewInit中即可。使用“严格”类型脚本时,
item[property]
将导致错误(假设
item
是某种类型的对象)。对于这些情况,我发现这个答案很有用:它是关于强制一个类型化的对象是“可索引的”。当我意识到我可以返回数字或字符串时,你的解决方案对我帮助最大。我的表有两种类型,需要对数字进行排序,而不像字符串。使用检查键入的三元运算符是解决方案的关键。我得到了
找不到name'\u isNumbervalue
,并且假设这是一个lodash方法,我在节点模块中找不到该方法<代码>isNumber
存在。我以前不熟悉lodash,如果这是什么。如何使用它?从“@angular/cdk/concurvation”导入{u isNumberValue};你能用fixWorks wonderfull更新stackblitz吗?但如果有