2016-04-12 55 views
5

Sto provando a creare un componente in cui è possibile passare quale pipe deve essere utilizzata per un elenco all'interno del componente. Da quello che ho potuto trovare testando e cercando in giro per le risposte l'unica soluzione sembra creare qualcosa di simile:Tubo dinamico in Angular 2

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

my-component modello:

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

Che poi le mappe myFilter alla logica del tubo corretto e lo esegue , ma questo sembra un po 'sporco e non ottimale.

Ho pensato che avrebbero trovato una soluzione migliore a questo problema dal momento che Angular 1 in cui si farebbe anche qualcosa in questo senso.

Non c'è un modo migliore per farlo in Angular 2?

+0

è getpipe il tuo filtro personalizzato? –

risposta

3

Purtroppo non la penso così. È lo stesso di angular1 dove hai una funzione restituisce una stringa per il Pipe dinamico che desideri.

Guardando i documenti è esattamente come lo mostrano anche loro.

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

Poi nel controller:

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

Ahimè, potrebbe essere peggio! :)

1

Sono riuscito a far funzionare qualcosa, è un po 'sporco e malvagio (con eval) ma fa il trucco per me. Nel mio caso, ho un componente tabella con diversi tipi di dati in ogni riga (ad esempio titolo, url, data, stato). Nel mio database, lo stato è contrassegnato come 1 come enabled o 0 per disabled. Certo, è più preferibile mostrare la funzione abilitata/disabilitata al mio utente. Inoltre, la mia colonna del titolo è multilingue, il che la rende un oggetto con en o id come chiave.

// Example row object: 
title: { 
    "en": "Some title in English", 
    "id": "Some title in Indonesian" 
}, 
status: 1 // either 1 or 0 

Idealmente, ho bisogno di 2 tubi diversi per convertire i miei dati per mostrare all'utente di mia app. Qualcosa come translateTitle e getStatus andrà bene. Chiamiamo la pipe del genitore 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] 
    } 
} 

Probabilmente otterrò molto odio nell'utilizzare eval. Spero che sia d'aiuto!

Aggiornamento: quando si potrebbe averne bisogno

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> 

tornerà:

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

Il modo più semplice per affrontare questo sarebbe non utilizzare i tubi nei modelli HTML, ma, invece, iniettare la pipa nel costruttore di un componente (usando DI), quindi applica la trasformazione funzionalmente. Funziona abbastanza bene con una mappa osservabile o stream rxjs simili.

+0

Buon suggerimento, tuttavia richiederebbe comunque un servizio wrapper se deve essere usato nel modo che preferisco. – Chrillewoodz

2

Sulla risposta di borislemke, ecco una soluzione che non ha bisogno di eval() e che sembra abbastanza pulito:

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 = []; 
}