2016-04-12 3 views
5

Ich versuche, eine Komponente zu erstellen, wo Sie übergeben können, welche Pipe für eine Liste innerhalb der Komponente verwendet werden soll. Von dem, was ich durch das Testen und schaut sich um nach Antworten die einzige Lösung scheint zu schaffen so etwas wie finden konnte:Dynamische Pipe in Angular 2

<my-component myFilter="sortByProperty"></my-component> 

my-component Vorlage:

<li *ngFor="#item of list | getPipe:myFilter"></li> 

die dann Karten myFilter auf die richtige Rohr Logik und führt es aus , aber das scheint ein bisschen dreckig und nicht optimal.

Ich dachte, sie hätten eine bessere Lösung für dieses Problem seit Angular 1, wo Sie auch etwas in dieser Richtung tun würden.

Gibt es keinen besseren Weg, dies in Angular 2 zu tun?

+0

ist getpipe Ihren benutzerdefinierten Filter? –

Antwort

3

Leider glaube ich nicht. Es ist das gleiche wie in angular1, wo Sie eine Funktion haben, die eine Zeichenfolge für die gewünschte dynamische Pipe zurückgibt.

Mit Blick auf die Dokumente, das ist genau, wie sie es auch zeigen.

https://angular.io/docs/ts/latest/guide/pipes.html

template: ` 
    <p>The hero's birthday is {{ birthday | date:format }}</p> 
    <button (click)="toggleFormat()">Toggle Format</button> 
` 

Dann in der Steuerung:

get format() { return this.toggle ? 'shortDate' : 'fullDate'} 

Ach, es könnte schlimmer sein! :)

1

Ich schaffte es etwas zu arbeiten, es ist ein bisschen dreckig und böse (mit Eval), aber es macht den Trick für mich. In meinem Fall habe ich eine Tabellenkomponente mit verschiedenen Datentypen in jeder Zeile (z. B. Titel, URL, Datum, Status). In meiner Datenbank ist der Status als 1 als enabled oder 0 für disabled markiert. Natürlich ist es mehr vorzuziehen, meinem Benutzer "aktiviert/deaktiviert" zu zeigen. Außerdem ist meine Titelspalte mehrsprachig, was es zu einem Objekt mit entweder en oder id macht, wie es der Schlüssel ist.

Idealerweise brauche ich 2 verschiedene Rohre, um meine Daten zu konvertieren, um sie dem Benutzer meiner App anzuzeigen. Etwas wie translateTitle und getStatus wird gut tun. Lass uns die Pipe der Eltern anrufen dynamicPipe.

/// some-view.html 
{{ title | dynamicPipe:'translateTitle' }} 
{{ status | dynamicPipe:'getStatus' }} 


/// dynamic.pipe.ts 
//...import Pipe and PipeTransform 

@Pipe({name:'dynamicPipe'}) 
export class DynamicPipe implements PipeTransform { 

    transform(value:string, modifier:string) { 
     if (!modifier) return value; 
     return eval('this.' + modifier + '(' + value + ')') 
    } 

    getStatus(value:string|number):string { 
     return value ? 'enabled' : 'disabled' 
    } 

    translateTitle(value:TitleObject):string { 
     // defaultSystemLanguage is set to English by default 
     return value[defaultSystemLanguage] 
    } 
} 

Ich werde wahrscheinlich eine Menge Hass auf die Verwendung von Eval bekommen. Ich hoffe es hilft!

Update: wenn Sie es brauchen könnte

posts = { 
    content: [ 
     { 
      title: 
       { 
        en: "Some post title in English", 
        es: "Some post title in Spanish" 
       }, 
      url: "a-beautiful-post", 
      created_at: "2016-05-15 12:21:38", 
      status: 1 
     }, 
     { 
      title: 
       { 
        en: "Some post title in English 2", 
        es: "Some post title in Spanish 2" 
       }, 
      url: "a-beautiful-post-2", 
      created_at: "2016-05-13 17:53:08", 
      status: 0 
     } 
    ], 
    pipes: ['translateTitle', null, 'humanizeDate', 'getStatus'] 
} 

<table> 
    <tr *ngFor="let row in posts"> 
     <td *ngFor="let column in row; let i = index">{{ column | dynamicPipe:pipes[i] }}</td> 
    </tr> 
</table> 

Wir kommen wieder:

| title   | url   | date   | status   | 
| Some post t... a-beautiful... an hour ago  enabled 
| Some post ...2 a-beautifu...2 2 days ago  disabled 
2

Der einfachste Weg, dies zu bewältigen wäre, nicht die Rohre in den HTML-Templates zu verwenden, sondern stattdessen injizieren die Pipe in den Konstruktor einer Komponente (unter Verwendung von DI), dann wenden Sie die Transformation funktional an. Dies funktioniert sehr gut mit einer Observable Map oder ähnlichen rxjs Streams.

+0

Guter Vorschlag, aber es würde immer noch einen Wrapper-Service erfordern, wenn es so verwendet werden soll, wie ich es möchte. – Chrillewoodz

2

Aufbauend auf borislemke Antwort, hier ist eine Lösung, die nicht eval() und die ich finden muss ziemlich sauber:

dynamic.pipe.ts:

import { 
    Injector, 
    Pipe, 
    PipeTransform 
} from '@angular/core'; 


@Pipe({ 
    name: 'dynamicPipe' 
}) 
export class DynamicPipe implements PipeTransform { 

    public constructor(private injector: Injector) { 
    } 

    transform(value: any, pipeToken: any, pipeArgs: any[]): any { 
     if (!pipeToken) { 
      return value; 
     } 
     else { 
      let pipe = this.injector.get(pipeToken); 
      return pipe.transform(value, ...pipeArgs); 
     } 
    } 
} 

app.module.ts:

// … 
import { DynamicPipe } from './dynamic.pipe'; 

@NgModule({ 
    declarations: [ 
    // … 
    DynamicPipe, 
    ], 
    imports: [ 
    // … 
    ], 
    providers: [ 
    // list all pipes you would like to use 
    PercentPipe, 
    ], 
    bootstrap: [AppComponent] 
}) 
export class AppModule { } 

app.component.ts:

import { Component, OnInit } from '@angular/core'; 
import { PercentPipe } from '@angular/common'; 

@Component({ 
    selector: 'app-root', 
    template: ` 
    The following should be a percentage: 
    {{ myPercentage | dynamicPipe: myPipe:myPipeArgs }} 
    `, 
    providers: [] 
}) 

export class AppComponent implements OnInit { 
    myPercentage = 0.5; 
    myPipe = PercentPipe; 
    myPipeArgs = []; 
}