如何使用Angular 2管道对对象列表进行排序

8

我正在尝试创建一个管道,用于对自定义类型的数组进行排序。

// custom-object.ts
export class CustomObject {
    constructor(
        public someString: string,
        public someNumber: number
    ) {}
}

我在HTML中的代码为:

// custom-object-form.component.ts
<div class="form-group">
    <label for="cricos_course_code">Object: </label>
    <select class="form-control" required [(ngModel)]="model.someString">
        <option *ngFor="#object of (customObjects | sortArrayOfCustomObjects)" [value]="object.someString">{{object.someString}}</option>
    </select>
</div>

接下来是管道的代码:

// sort-custom-object.pipe.ts
import {Pipe, PipeTransform} from 'angular2/core';
import {CustomObject} from '../custom-object';

@Pipe({name: 'sortArrayOfCustomObjects'})
export class SortArrayOfCustomObjectsPipe implements PipeTransform {
  transform(arr:Array<CustomObject>): any {
    return arr.sort((a, b) => {
      if (a.someString > b.someString) {
        return 1;
      }
      if (a.someString < b.someString) {
        return -1;
      }
      // a must be equal to b
      return 0;
    });
  }
}

现在我在控制台中收到一个错误信息:
EXCEPTION: TypeError: Cannot read property 'sort' of undefined in [(customObjects | sortArrayOfCustomObjects) in FormComponent@7:24]

你是否在寻找 args: Array<string | number> - SnareChops
更贴近于参数: Array<CustomObject.someString | CustomObject.someNumber>。然后在我的排序函数中(似乎不起作用?),我可以根据提供的参数更改排序方式。 - Allan Chau
Array<CustomObject.someString | CustomObject.someNumber> 的问题在于它们是属性而不是类型CustomObject.someString类型string。因此,您不能使用CustomObject.someString作为类型。您能否提供更多关于您需求的信息? - SnareChops
我有一个对象数组,包含属性p1:string,p2:number等。在我的表单中,我想要有两个选择字段,按字母顺序显示p1列表和按降序显示p2列表。我认为我可以使用管道,例如*ngFor="item of items | sortItems" - Allan Chau
1个回答

9

根据您提供的有限信息,我认为您需要以下内容。

@Pipe({name: 'sortArrayOfCustomObjects'})
export class SortArrayOfCustomObjectsPipe implements PipeTransform {

  transform(arr: CustomObject[], args: any): CustomObject[]{
    return arr.sort((a, b) => {
      if (a.p1 > b.p1 || a.p2 < b.p2) {
        return 1;
      }
      if (a.p1 < b.p1 || a.p2 > b.p2) {
        return -1;
      }
      return 0;
    });
  }
}

这将首先按照p1进行对象排序,然后按照p2进行排序。例如。
{p1: 'AA', p2: 3},
{p1: 'CC', p2: 2},
{p1: 'BB', p2: 5},
{p1: 'BB', p2: 1},
{p1: 'AA', p2: 2},
{p1: 'DD', p2: 4}

将被分类到

{p1: 'AA', p2: 3},
{p1: 'AA', p2: 2},
{p1: 'BB', p2: 5},
{p1: 'BB', p2: 1},
{p1: 'CC', p2: 2},
{p1: 'DD', p2: 4}

这是基于你的评论:
我有一个对象数组,包含属性p1:字符串、p2:数字等。在我的表单中,我想要有两个选择字段,按字母顺序显示p1列表和按降序显示p2列表。
用法如下:
*ngFor="#item of (items | sortArrayOfCustomObjects)"

更新

针对您目前收到的错误,请确保使用 guard 防止在数组中出现 undefined 值。

transform(arr: CustomObject[], args: any): CustomObject[]{
  if(!arr){ return; }
  ...
}

谢谢,我收到一个TypeError:arr未定义...?这是什么原因导致的?但如果我在我的transform方法中只返回arr,代码就能正常工作。 - Allan Chau
更新答案以包含使用括号(在Angular文档此处靠近底部找到)。 - SnareChops
我尝试了括号,但错误仍然出现。我已经更新了问题,尝试提供更多细节。 - Allan Chau
你能否发布组件代码相关部分,你在哪里赋值“customObjects”,有可能你没有给它赋一个值吗?或者是一个异步问题。您可以通过transform函数中的if语句来防范这种情况,该语句检查arr是否为undefined,如果是,则在到达arr.sort(...)行之前返回空数组或undefined - SnareChops
啊,就是这个!'if (arr === undefined) { return arr; } else { ... }' 是行得通的。在这里提到的有状态的 AsyncPipe 最佳实践是使用吗?https://angular.io/docs/ts/latest/guide/pipes.html - Allan Chau
只有当你的数据是一个 Promise 或者 Observable 才能使用它。否则,使用它也会导致错误。 - SnareChops

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接