Angular 角度2中的动态管道
我试图创建一个组件,您可以在其中传递应该用于组件内部列表的管道。通过测试和四处寻找答案,我发现唯一的解决方案似乎是:Angular 角度2中的动态管道,angular,angular2-pipe,Angular,Angular2 Pipe,我试图创建一个组件,您可以在其中传递应该用于组件内部列表的管道。通过测试和四处寻找答案,我发现唯一的解决方案似乎是: <my-component myFilter="sortByProperty"></my-component> 然后将myFilter映射到正确的管道逻辑并运行它,但这似乎有点脏,而且不是最佳的 我想他们会想出一个更好的解决方案,因为Angular 1,你也会沿着这条线做一些事情 在Angular 2中没有更好的方法吗?不幸的是,我不这么认为。这与ang
<my-component myFilter="sortByProperty"></my-component>
然后将myFilter
映射到正确的管道逻辑并运行它,但这似乎有点脏,而且不是最佳的
我想他们会想出一个更好的解决方案,因为Angular 1,你也会沿着这条线做一些事情
在Angular 2中没有更好的方法吗?不幸的是,我不这么认为。这与angular1中的相同,在angular1中,有一个函数返回所需动态管道的字符串 看看这些文档,它们也正是这样显示的
唉,情况可能更糟!:) 我设法让一些东西起作用了,它有点肮脏和邪恶(使用eval),但它对我来说起了作用。在我的例子中,我有一个表组件,每行有不同的数据类型(例如标题、url、日期、状态)。在我的数据库中,状态标记为
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
理想情况下,我需要两个不同的管道来转换我的数据以显示给我的应用程序的用户。像translateTitle
和getStatus
这样的东西就可以了。让我们调用父管道dynamicpe
/// 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>
解决这个问题的最简单方法是不在HTML模板中使用管道,而是将管道注入组件的构造函数(使用DI),然后在功能上应用转换。这对于可观察地图或类似的rxjs流非常有效。基于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 { }
import { DatePipe } from '@angular/common';
import { PipeInjectorComponent } from './pipe-injector.component';
@NgModule({
declarations: [
PipeInjectorComponent,
],
imports: [
],
providers: [
DatePipe,
],
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 = [];
}
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);
}
}
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) {}
}
在@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;
}
}
}
我通过将管道提供程序发送到组件并运行transform方法来处理这个问题。它对角9有效。我希望它能帮助别人!演示: 管式喷油器.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 = [];
}
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);
}
}
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) {}
}
getpipe是您的自定义过滤器吗?您不仅可以在AngularJS中执行此操作,还可以在Angular+2中执行此操作。该技术类似于@Balu在下面发布的内容。建议不错,但是如果要按我想要的方式使用,它仍然需要一个包装服务。我无法让它工作。我得到以下错误
error:StaticInjectorError(AppModule)[date]:StaticInjectorError(Platform:core)[date]:NullInjectorError:日期没有提供程序
@Chuck是否已将日期管道
添加到应用程序模块的提供程序?我的所有管道都通过app.module中提供的shared.module导出。当我像上面那样实现代码时,它就工作了。然而,我在代码中将myPipe设置为@Input()管道
,以便可以使用它generically@Chuck如果您找到了答案,请评论或添加一个答案,说明您是如何找到答案的。其他人也想知道。我必须在将排列(…)应用于pipeArgs之前,向pipeArgs添加一个检查,以确保它是一个数组,否则它不会为我的非动态管道提供argsif(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之后,我遇到了一些问题。
import { DatePipe } from '@angular/common';
import { PipeInjectorComponent } from './pipe-injector.component';
@NgModule({
declarations: [
PipeInjectorComponent,
],
imports: [
],
providers: [
DatePipe,
],
bootstrap: [AppComponent]
})
export class AppModule { }