2016-03-10 4 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

Можете ли вы создать быстрый bin, поэтому фрагмент можно воспроизвести. –

ответ

7

Встраиваемая труба async вводит ChangeDetectorRef и звонит markForCheck() на нее, когда обещание разрешается. Чтобы сделать это в одной трубе, вы должны следовать этому примеру. Вы можете просмотреть источник TypScript для этого here.

Я бы посоветовал, однако, забыть об обращении с асинхронной настройкой самостоятельно и вместо этого написать чистую сортировочную трубу без состояния и связать ее со встроенной трубкой async. Для этого, вы бы написать трубу для обработки голого Array, а не обещание, и использовать его как это:

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

Я изначально пробовал это; однако я столкнулся с проблемами - я думаю, потому что моя труба вызывалась до того, как обещание было разрешено, поэтому мой массив array.sort выдал ошибку. Возможно, мне просто нужно обработать пустой массив, чтобы начать с учета задержки в разрешенном массиве. Я сделаю это. – RHarris

+2

@RHarris Труба 'async' возвращает значение null до того, как обезвреживание будет разрешено, поэтому вашему трубу нужно будет обрабатывать значение null без ошибок для цепочки для работы. – Douglas

+0

@Douglas Спасибо за 'null'hint .. Я заметил это поведение, но я подумал, что я ошибся и, таким образом, получил« нуль ». Но, конечно, это желаемое поведение для еще не разрешенного обещания;) – 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 ('значение'); }, 3000); return sub; Это краткая версия того, что вам нужно. Трубы подталкивают свои значения от одного к другому. Затем BehaviorSubject может быть подключен к асинхронной трубе угловой. –

Смежные вопросы