angularangular2-pipe

Dynamic pipe in Angular 2


I'm trying to create a component where you can pass which pipe that should be used for a list inside the component. From what I could find by testing and looking around for answers the only solution appears to create something like:

<my-component myFilter="sortByProperty"></my-component>

my-component template:

<li *ngFor="#item of list | getPipe:myFilter"></li>

Which then maps myFilter to the correct pipe logic and runs it, but this seems a bit dirty and not optimal.

I thought they would have come up with a better solution to this problem since Angular 1 where you would also do something along these lines.

Is there not a better way to do this in Angular 2?


Solution

  • Building on borislemke's answer, here's a solution which does not need eval() and which I find rather clean:

    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 = [];
    }