Angular 2中的动态管道
Posted
技术标签:
【中文标题】Angular 2中的动态管道【英文标题】:Dynamic pipe in Angular 2 【发布时间】:2016-08-02 13:49:45 【问题描述】:我正在尝试创建一个组件,您可以在其中传递应该用于组件内列表的管道。通过测试和四处寻找答案,我发现唯一的解决方案似乎是:
<my-component myFilter="sortByProperty"></my-component>
my-component
模板:
<li *ngFor="#item of list | getPipe:myFilter"></li>
然后将myFilter
映射到正确的管道逻辑并运行它,但这似乎有点脏并且不是最佳的。
我认为自 Angular 1 以来他们会想出一个更好的解决方案来解决这个问题,你也可以按照这些思路做一些事情。
在 Angular 2 中没有更好的方法吗?
【问题讨论】:
getpipe 是您的自定义过滤器吗? 不仅可以在 AngularJS 中执行此操作,还可以在 Angular +2 中执行此操作。该技术类似于下面@Balu 发布的技术。 【参考方案1】:基于 borislemke 的回答,这是一个不需要 eval()
的解决方案,我觉得它相当干净:
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 = [];
【讨论】:
我无法让它工作。我收到以下错误Error: StaticInjectorError(AppModule)[date]: StaticInjectorError(Platform: core)[date]: NullInjectorError: No provider for date!
@Chuck 您是否将DatePipe
添加到您的应用模块的提供程序中?
我所有的管道都是通过 app.module 中提供的 shared.module 导出的。当我按照上面的方式实现代码时,它就可以工作了。但是我在我的代码中将 myPipe 设置为 @Input() pipe
以便可以通用
@Chuck 如果你想出了答案,请评论或添加你所做的答案。其他人也想知道。
在对它应用展开 (...) 之前,我必须对 pipeArgs 添加一个检查以确保它是一个数组,否则它不会为我的非动态管道提供 args。 if (Array.isArray(pipeArgs)) return pipe.transform(value, ...pipeArgs); else return pipe.transform(value, pipeArgs);
它曾经在带有 Typescript 3.1.6 的 Angular 7 中运行良好,但自从使用 Typescript 3.5.3 升级到 Angular 8 后,我遇到了问题。【参考方案2】:
我设法让一些东西工作,它有点肮脏和邪恶(使用 eval)但它对我有用。就我而言,我有一个表格组件,每一行都有不同的数据类型(例如标题、网址、日期、状态)。在我的数据库中,状态标记为1
为enabled
或0
为disabled
。当然,最好向我的用户显示启用/禁用。另外,我的标题栏是多语言的,这使它成为一个以en
或id
为键的对象。
// Example row object:
title:
"en": "Some title in English",
"id": "Some title in Indonesian"
,
status: 1 // either 1 or 0
理想情况下,我需要 2 个不同的管道来转换我的数据以显示给我的应用程序的用户。像translateTitle
和getStatus
这样的东西就可以了。让我们调用父管道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]
我可能会对使用 eval 感到非常讨厌。希望对您有所帮助!
更新:当你可能需要它时
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>
将返回:
| title | url | date | status |
| Some post t... a-beautiful... an hour ago enabled
| Some post ...2 a-beautifu...2 2 days ago disabled
【讨论】:
【参考方案3】:解决此问题的最简单方法是不在 HTML 模板中使用管道,而是将管道注入组件的构造函数(使用 DI),然后在功能上应用转换。这适用于 Observable 地图或类似的 rxjs 流。
【讨论】:
好建议,但是如果要按我想要的方式使用它仍然需要包装服务。【参考方案4】:不幸的是,我不这么认为。这与 angular1 中的相同,其中您有一个函数为您想要的动态管道返回一个字符串。
查看文档,这正是他们展示的方式。
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>
`
然后在控制器中:
get format() return this.toggle ? 'shortDate' : 'fullDate'
唉,情况可能更糟! :)
【讨论】:
【参考方案5】:在 @Balu 的基础上回答这个我必须做的事情才能让它与 Angular 9 一起工作
import Injector, Pipe, PipeTransform from '@angular/core';
import PercentPipe, CurrencyPipe, DecimalPipe from '@angular/common';
@Pipe(
name: 'dynamicPipe'
)
export class DynamicPipe implements PipeTransform
public constructor(private injector: Injector, private percentPipe: PercentPipe)
transform(value: any, pipeToken: any, pipeArgs: any[]): any
const MAP = 'currency': CurrencyPipe, 'decimal': DecimalPipe, 'percent': PercentPipe
if (pipeToken && MAP.hasOwnProperty(pipeToken))
var pipeClass = MAP[pipeToken];
var pipe = this.injector.get(pipeClass);
if (Array.isArray(pipeArgs))
return pipe.transform(value, ...pipeArgs);
else
return pipe.transform(value, pipeArgs);
else
return value;
【讨论】:
【参考方案6】:我通过将管道提供程序发送到组件并运行转换方法来处理这个问题。它适用于 Angular 9。我希望它对某人有所帮助!演示:https://stackblitz.com/edit/angular-kdqc5e
pipe-injector.component.ts:
import Component, OnInit, Input, PipeTransform from '@angular/core';
@Component(
selector: 'pipe-injector',
template: `
Should inject my pipe provider
getText()
`,
providers: []
)
export class PipeInjectorComponent
@Input() pipeProvider: PipeTransform;
@Input() pipeArgs: Array<any>;
@Input() textToFormat: string;
getText()
return this.pipeProvider.transform(this.textToFormat, ...this.pipeArgs);
应用组件.ts:
import Component, OnInit from '@angular/core';
import DatePipe from '@angular/common';
@Component(
selector: 'app-root',
template: `
<pipe-injector [pipeProvider]="pipeProvider" [pipeArgs]="pipeArgs" textToFormat='05-15-2020'>
</pipe-injector>
`,
providers: []
)
export class AppComponent implements OnInit
pipeArgs = ['dd/MM/yyyy'];
constructor(public pipeProvider: DatePipe)
app.module.ts:
import DatePipe from '@angular/common';
import PipeInjectorComponent from './pipe-injector.component';
@NgModule(
declarations: [
PipeInjectorComponent,
],
imports: [
],
providers: [
DatePipe,
],
bootstrap: [AppComponent]
)
export class AppModule
【讨论】:
以上是关于Angular 2中的动态管道的主要内容,如果未能解决你的问题,请参考以下文章