在 运行 时间内使用管道名称/元数据调用管道
invoke pipe during run time using pipe name /metadata
我正在尝试构建一个动态 table,我想在 运行 时间 中决定使用哪个管道(如果有的话)。
我正在尝试实现类似于(简体)的东西:
export class CellModel {
public content: any;
public pipe: string
}
Table
<tbody>
<tr *ngFor="let row of data">
<template ngFor let-cell [ngForOf]=row>
<td *ngIf="cell.pipe">{{cell.content | cell.pipe}}</td>
<td *ngIf="!cell.pipe">{{cell.content}}</td>
</tr>
</tbody>
我知道这个例子出错了。我可以使用 Reflect 是某种方式还是其他解决方案?
您不能动态应用管道。您可以做的是构建一个 "meta" 管道来决定要执行的转换。
@Pipe({
name: 'meta'
})
class MetaPipe implements PipeTransform {
transform(val, pipes:any[]) {
var result = val;
for(var pipe of pipes) {
result = pipe.transform(result);
}
return result;
}
}
然后像
一样使用它
<td *ngIf="cell.pipe">{{cell.content | meta:[cell.pipe]}}</td>
对于仅运行时编译,您可以创建一个动态编译模板的指令。
更新:
将compileModuleAndAllComponentsAsync
用于RC.6^
动态-pipe.ts
ngAfterViewInit() {
const data = this.data.content;
const pipe = this.data.pipe;
@Component({
selector: 'dynamic-comp',
template: '{{ data | ' + pipe + '}}'
})
class DynamicComponent {
@Input() public data: any;
};
@NgModule({
imports: [BrowserModule],
declarations: [DynamicComponent]
})
class DynamicModule {}
this.compiler.compileModuleAndAllComponentsAsync(DynamicModule)
.then(({moduleFactory, componentFactories}) => {
const compFactory = componentFactories.find(x => x.componentType === DynamicComponent);
const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
const cmpRef = this.vcRef.createComponent(compFactory, 0, injector, []);
cmpRef.instance.data = data;
});
}
过时的解决方案
在 RC.5 中,您可以使用 Compiler.compileComponentSync/Async
来做到这一点:
动态-pipe.ts
@Directive({
selector: 'dynamic-pipe'
})
export class DynamicPipe {
@Input() data: CellModel;
constructor(private vcRef: ViewContainerRef, private compiler: Compiler) {}
ngAfterViewInit() {
const metadata = new ComponentMetadata({
template: '{{ data | ' + this.data.pipe + '}}'
});
const data = this.data.content;
const decoratedCmp = Component(metadata)(class DynamicComponent { data = data; });
this.compiler.compileComponentAsync(decoratedCmp)
.then(factory => {
const injector = ReflectiveInjector.fromResolvedProviders([],
this.vcRef.parentInjector);
this.vcRef.createComponent(factory, 0, injector, []);
});
}
}
并这样使用:
<template ngFor let-cell [ngForOf]="row">
<td><dynamic-pipe [data]="cell"></dynamic-pipe></td>
</template>
另请参阅演示此功能的 plunker sample RC.5。
无论如何我认为 Günter 的解决方案更可取
我正在尝试构建一个动态 table,我想在 运行 时间 中决定使用哪个管道(如果有的话)。
我正在尝试实现类似于(简体)的东西:
export class CellModel {
public content: any;
public pipe: string
}
Table
<tbody>
<tr *ngFor="let row of data">
<template ngFor let-cell [ngForOf]=row>
<td *ngIf="cell.pipe">{{cell.content | cell.pipe}}</td>
<td *ngIf="!cell.pipe">{{cell.content}}</td>
</tr>
</tbody>
我知道这个例子出错了。我可以使用 Reflect 是某种方式还是其他解决方案?
您不能动态应用管道。您可以做的是构建一个 "meta" 管道来决定要执行的转换。
@Pipe({
name: 'meta'
})
class MetaPipe implements PipeTransform {
transform(val, pipes:any[]) {
var result = val;
for(var pipe of pipes) {
result = pipe.transform(result);
}
return result;
}
}
然后像
一样使用它<td *ngIf="cell.pipe">{{cell.content | meta:[cell.pipe]}}</td>
对于仅运行时编译,您可以创建一个动态编译模板的指令。
更新:
将compileModuleAndAllComponentsAsync
用于RC.6^
动态-pipe.ts
ngAfterViewInit() {
const data = this.data.content;
const pipe = this.data.pipe;
@Component({
selector: 'dynamic-comp',
template: '{{ data | ' + pipe + '}}'
})
class DynamicComponent {
@Input() public data: any;
};
@NgModule({
imports: [BrowserModule],
declarations: [DynamicComponent]
})
class DynamicModule {}
this.compiler.compileModuleAndAllComponentsAsync(DynamicModule)
.then(({moduleFactory, componentFactories}) => {
const compFactory = componentFactories.find(x => x.componentType === DynamicComponent);
const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
const cmpRef = this.vcRef.createComponent(compFactory, 0, injector, []);
cmpRef.instance.data = data;
});
}
过时的解决方案
在 RC.5 中,您可以使用 Compiler.compileComponentSync/Async
来做到这一点:
动态-pipe.ts
@Directive({
selector: 'dynamic-pipe'
})
export class DynamicPipe {
@Input() data: CellModel;
constructor(private vcRef: ViewContainerRef, private compiler: Compiler) {}
ngAfterViewInit() {
const metadata = new ComponentMetadata({
template: '{{ data | ' + this.data.pipe + '}}'
});
const data = this.data.content;
const decoratedCmp = Component(metadata)(class DynamicComponent { data = data; });
this.compiler.compileComponentAsync(decoratedCmp)
.then(factory => {
const injector = ReflectiveInjector.fromResolvedProviders([],
this.vcRef.parentInjector);
this.vcRef.createComponent(factory, 0, injector, []);
});
}
}
并这样使用:
<template ngFor let-cell [ngForOf]="row">
<td><dynamic-pipe [data]="cell"></dynamic-pipe></td>
</template>
另请参阅演示此功能的 plunker sample RC.5。
无论如何我认为 Günter 的解决方案更可取