可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm trying to create a component where you can pass which pipe that should be used for a list inside the component. From what I could find by testing and looking around for answers the only solution appears to create something like:
<my-component myFilter="sortByProperty"></my-component>
my-component
template:
<li *ngFor="#item of list | getPipe:myFilter"></li>
Which then maps myFilter
to the correct pipe logic and runs it, but this seems a bit dirty and not optimal.
I thought they would have come up with a better solution to this problem since Angular 1 where you would also do something along these lines.
Is there not a better way to do this in Angular 2?
回答1:
Unfortunately I don't think so. It's the same as in angular1 where you have a function return a string for the dynamic Pipe you want.
Looking at the docs that's exactly how they show it as well.
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> `
Then in the controller:
get format() { return this.toggle ? 'shortDate' : 'fullDate'}
Alas, it could be worse! :)
回答2:
Building on borislemke's answer, here's a solution which does not need eval()
and which I find rather clean:
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 = []; }
回答3:
I managed to get something working, it's a bit dirty and evil (with eval) but it does the trick for me. In my case, I have a table component with different data types in each row (e.g title, url, date, status). In my database, status is marked as either 1
as enabled
or 0
for disabled
. Of course, it is more preferable to be showing enabled/disabled to my user. Also, my title column is multilingual, which makes it an object with either en
or id
as it's key.
// Example row object: title: { "en": "Some title in English", "id": "Some title in Indonesian" }, status: 1 // either 1 or 0
Ideally, I need 2 different pipes to convert my data to show to my app's user. Something like translateTitle
and getStatus
will do fine. Let's call the parent's pipe 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] } }
I'll probably get a lot of hate on using eval. Hope it helps!
Update: when you might need it
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>
Will return:
| title | url | date | status | | Some post t... a-beautiful... an hour ago enabled | Some post ...2 a-beautifu...2 2 days ago disabled
回答4:
The easiest way to tackle this would be to not use the pipes in the HTML templates, but instead, inject the pipe into a component's constructor (using DI), then apply the transform functionally. This works quite well with an Observable map or similar rxjs streams.