2016-03-10 8 views
5

Ich versuche, eine benutzerdefinierte Pipe in Angular 2 zu erstellen, die ein Array von Objekten sortiert. Ich habe ein wenig Hilfe von this post gesammelt. Jedoch kann ich nicht scheinen, dass das funktioniert.Implementieren einer asynchronen Sortierröhre in Angular 2

Mein Rohr sieht wie folgt aus:

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

Die Verwendung des Rohres würde wie folgt aussehen:

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

Es ist wie der Blick nie mitgeteilt wird, dass das Versprechen gelöst hat und Daten haben ist zurückgekommen.

Was fehlt mir?

+1

Können Sie bitte eine schnelle erstellen bin so, dass das Snippet herum gespielt werden kann. –

Antwort

7

Das eingebaute async Rohr injiziert ein ChangeDetectorRef und ruft markForCheck() darauf auf, wenn das Versprechen verrechnet wird. Um alles in einer Pipe zu machen, sollten Sie diesem Beispiel folgen. Sie können die Typescript-Quelle für das here anzeigen.

Ich würde jedoch vorschlagen, über asynchronen Umgang allein zu vergessen und stattdessen eine reine staatslose Sortierrohr und schreiben Sie es mit der eingebauten async Rohr. Dafür würde schreiben Sie Ihre Pfeife mit einem nackten Array, kein Versprechen, und verwenden Sie es wie folgt zu behandeln:

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

Ich hatte das ursprünglich versucht; Ich stieß jedoch auf Probleme - ich denke, weil meine Pipe aufgerufen wurde, bevor das Versprechen gelöst wurde, so dass mein 'array.sort' einen Fehler verursachte. Vielleicht muss ich nur ein leeres Array behandeln, um die Verzögerung im aufgelösten Array zu berücksichtigen. Ich gebe das eine Chance. – RHarris

+2

@RHarris Die 'async' Pipe gibt null zurück, bevor das Versprechen aufgelöst wird. Daher muss Ihre Pipe null verarbeiten, ohne dass ein Fehler auftritt, damit die Verkettung funktioniert. – Douglas

+0

@Douglas Danke für den 'null'hint .. Ich habe dieses Verhalten bemerkt, aber ich dachte ich habe einen Fehler gemacht und damit' null' .. Aber natürlich ist es das gewünschte Verhalten für ein noch nicht gelöstes Versprechen;) – wzr1337

1

kann einfach ein BehaviorSubject aus Ihrem Rohr, das dann mit Winkel async Rohr gebunden bekommen kann.

Kleines Beispiel (setzen Sie es in Ihrem Transformationsmethode Ihrer Pfeife), die Sie sollten geben ‚Wert‘ nach 3 Sekunden:

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

Komplettes Beispiel:

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

Hey, Mann, du kannst den Code nicht aus dem Kontext streichen.Es gibt keine Informationen über 'FormsReflector', obwohl ich seine Funktionalität erraten könnte. Für deine Inspiration, +1. –

+0

Ja, wichtig ist, dass Sie ein BehaviorSubject aus Ihrer Pipe zurückgeben. So können Sie den Wert jederzeit ausfüllen und es wird widergespiegelt: const sub = new BehaviorSubject (null); setTimeout (() => { sub.next ('Wert'); }, 3000); Rückleitung sub; Dies ist die Kurzversion von dem, was Sie brauchen. Pipes schieben ihre Werte von einem zum anderen. Das BehaviorSubject kann dann an eine asynchrone Pipe von angular übergeben werden. –