Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

invoke pipe during run time using pipe name /metadata

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?

like image 522
royB Avatar asked Aug 31 '16 14:08

royB


People also ask

What does .pipe do in Angular?

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.

What is pipe demonstrate the code for pipes in Angular?

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.


2 Answers

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>
like image 62
Günter Zöchbauer Avatar answered Nov 15 '22 07:11

Günter Zöchbauer


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

like image 32
yurzui Avatar answered Nov 15 '22 08:11

yurzui