I'm trying to build a dynamic table where i wand to decide in run time which pipe to use (If Any).
I'm trying to achieve something similar to (Simplified):
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>
I understand that this example gives an error. Can i use Reflect is some manner or some other solution?
Use pipes to transform strings, currency amounts, dates, and other data for display. Pipes are simple functions to use in template expressions to accept an input value and return a transformed value. Pipes are useful because you can use them throughout your application, while only declaring each pipe once.
In Angular 2, Pipes are mainly used to change the data display format. By using the Pipe operator (|), we can apply the Pipe's features to any of the property in our Angular project. In addition to that, we can also chain pipe and pass parameters to the Pipe.
You can't apply pipes dynamically. What you can do is to build a "meta" pipe that decides what transformation(s) to do.
@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;
}
}
and then use it like
<td *ngIf="cell.pipe">{{cell.content | meta:[cell.pipe]}}</td>
For runtime compile only you can create a directive which will compile template dynamically.
UPDATE:
Using compileModuleAndAllComponentsAsync
for RC.6^
dynamic-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;
});
}
Plunker sample RC.6^
OBSOLETE SOLUTION
In RC.5 you can use Compiler.compileComponentSync/Async
to do that:
dynamic-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, []);
});
}
}
And use it this way:
<template ngFor let-cell [ngForOf]="row">
<td><dynamic-pipe [data]="cell"></dynamic-pipe></td>
</template>
See also the plunker sample RC.5 that demonstrates this feature.
Anyway i think Günter's solution is preferable
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With