2016-03-10 43 views
5

我正在尝试在Angular 2中创建一个自定义管道,它将对对象数组进行排序。我从this post获得了一些帮助。但是,我似乎无法得到这个工作。在Angular 2中实现异步排序管道

我管看起来是这样的:

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

它的观点一样,永远不会通知该承诺已经解决,数据已经回。

我错过了什么?

+1

能否请您创建一个快速所以这个片段可以被播放。 –

回答

7

内建的async管道注入一个ChangeDetectorRef并在承诺解决时调用markForCheck()。要在一个管道中完成所有操作,应遵循该示例。您可以查看here的Typescript源文件。

但是,我建议您忘记自己处理异步问题,而是编写一个纯粹的无状态分拣管道,并将其与内置的async管道连接起来。对于这一点,你会写你的管道来处理裸露Array,而不是一个承诺,像这样使用:

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

我原本试过这个;然而,我遇到了一些问题 - 我想是因为我的管道在promise解决之前被调用,所以我的'array.sort'抛出一个错误。也许我只需要处理一个空数组,以开始解决解析数组中的延迟。我会给你一个镜头。 – RHarris

+2

@RHarris''async'' pipe在promise解决之前返回null,所以你的管道需要处理null而不会出错以便链接工作。 – Douglas

+0

@Douglas感谢您的'null'提示..我注意到了这种行为,但我认为我是一个错误,因此得到了'null'..但当然这是一个尚未解决的承诺所期望的行为;) – wzr1337

1

简单地返回一个BehaviorSubject你的管道,然后可以用角异步管道获取绑定的。

小例子(把它放在你管你的变换方法),这应该给你的“价值”在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; 
    } 
} 
+0

嘿,伙计,你不能在上下文中放一些代码。没有关于'FormsReflector'的信息,尽管我可能猜测它的功能。为了您的灵感,+1。 –

+0

是的,所以重要的是你应该从管道中返回一个BehaviorSubject。因此,您可以随时填写该值,并且将反映出来: const sub = new BehaviorSubject(null); setTimeout(()=> {sub.next('value'); },3000); return sub; 这是您需要的简短版本。管道正在将他们的价值观从一个推向另一个。 BehaviorSubject然后可以通过管道传输到角度异步管道。 –