在Angular 2中实现异步排序管道

时间:2016-03-10 22:15:43

标签: angular

我正在尝试在Angular 2中创建一个自定义Pipe,它将对一组对象进行排序。我从this post获得了一些帮助。但是,我似乎无法使其发挥作用。

我的烟斗看起来像这样:

@Pipe({
  name: "orderByAsync",
  pure: false
})
export class AsyncArrayOrderByPipe  {
  private _promise : Promise<Array<Object>>;
  private _output: Array<Object>;

  transform(promise: Promise<Array<Object>>, args: any): Array<Object>{
    var _property : string = "";
    var _descending : boolean = false;

    this._property = args[0]["property"] || "";
    this._descending = args[0]["descending"] || false;

    if(!this._promise) {
      this._promise = promise.then((result) => {
        result.sort((a: any, b: any) => {
          if (a[this._property] < b[this._property])  return (this._descending ? 1: -1);
          else if (a[this._property] > b[this._property]) return (this._descending ? -1: 1);
          else return 0;
        });

        this._output = result;
      });
    }

    return this._output;
  }
}

管道的使用如下所示:

<div *ngFor="#c of countries | orderByAsync">{{c.name}}</div>

就像从未通知视图已经解决了承诺并且已经返回数据。

我错过了什么?

2 个答案:

答案 0 :(得分:13)

内置async管道会在promise解析时注入ChangeDetectorRef并在其上调用markForCheck()。要在一个管道中完成所有操作,您应该遵循该示例。您可以查看here的Typescript源。

但是,我建议忘记自己处理异步,而是写一个纯无状态排序管道并用内置的async管道链接它。为此,您可以编写管道以处理裸Array,而不是承诺,并像这样使用它:

<div *ngFor="#c of countries | async | orderBy">{{c.name}}</div>

答案 1 :(得分:1)

只需将一个BehaviorSubject从管道中返回,然后可以使用角度异步管道绑定。

小例子(把它放在管道的变换方法中)应该给你的价值&#39; 3秒后:

const sub = new BehaviorSubject(null);
setTimeout(() => { sub.next('value'); }, 3000);
return sub;

完整示例:

import { IOption } from 'somewhere';
import { FormsReflector } from './../forms.reflector';
import { BehaviorSubject } from 'rxjs';
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({ name: 'getOptions' })
export class GetOptionsPipe implements PipeTransform  {

  public transform(value, ...args: any[]) {
    const _subject = new BehaviorSubject('-');
    if (args.length !== 2) {
      throw `getOptions pipe needs 2 arguments, use it like this: {{ 2 | getOptions:contract:'contractType' | async }}`;
    }
    const model = args[0];
    if (typeof model !== 'object') {
      throw `First argument on getOptions pipe needs to be the model, use it like this: {{ 2 | getOptions:contract:'contractType' | async }}`;
    }
    const propertyName = args[1];
    if (typeof propertyName !== 'string') {
      throw `Second argument on getOptions pipe needs to be the property to look for, ` +
        `use it like this: {{ 2 | getOptions:contract:'contractType' | async }}`;
    }
    const reflector = new FormsReflector(model);
    reflector.resolveOption(propertyName, value)
    .then((options: IOption) => {
      _subject.next(options.label);
    })
    .catch((err) => {
      throw 'getOptions pipe fail: ' + err;
    });
    return _subject;
  }
}