kob490
kob490

Reputation: 3317

How to dynamically inject or load a pipe in Angular 8?

I have the following custom pipe in my Angular 8 app:

import { Pipe, PipeTransform } from '@angular/core';
import { MyService} from '../_services/my.service';

@Pipe({
    name: 'myPipe'
})
export class MyPipe implements PipeTransform {
    constructor(private myService: MyService) {}

    transform(value: string): any {
        return this.myService.loadForID(value);
    }
}

I am trying to transform a value dynamically in a component code, by having the string name only: 'myPipe' but i cannot find anyway to inject/load a pipe dynamically for a string. an online post that i found suggests the following code, but even this seem to require a type (MyService) and not a string

constructor(private injector:Injector) {
  injector.get(MyService);
}

is there a way to achieve this in Angular?

Upvotes: 2

Views: 2700

Answers (1)

spots
spots

Reputation: 2708

In you app.module you can use a string:

@NgModule({
  imports:      [ BrowserModule, FormsModule ],
  declarations: [ AppComponent, HelloComponent ],
  bootstrap:    [ AppComponent ],
  providers: [
    MyPipe,
    { provide: 'myPipe', useClass: MyPipe }
  ]
})
export class AppModule { }

Then, you can inject it into your component:

import { Component, Injector } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular';

  constructor(private injector:Injector){
    var myInterface = injector.get('myPipe');
    myInterface.transform('test');
  }  
}

Here's a stackblitz showing the example

EDIT

If you want to avoid the deprecated call to injector.get but still be able to access the service from the injector with a string, you can use a service to figure out which injection token should be used. I don't think this is the prettiest way to do it, but I think it meets OPs needs.

First create a Service to map a string to the expected injection token:

@Injectable()
export class TokenService {
  static MY_PIPE_TOKEN = new InjectionToken<MyPipe>('myPipe');

  getToken(name: string): InjectionToken<any> {
    if (name === 'myPipe') {
      return TokenService.MY_PIPE_TOKEN;
    } else {
      throw `No token with name ${name} found`;
    }
  }
}

Set up your providers, using the Injection Token from the Service:

@NgModule({
  imports:      [ BrowserModule, FormsModule ],
  declarations: [ AppComponent, HelloComponent ],
  bootstrap:    [ AppComponent ],
  providers: [
    TokenService,
    MyPipe,
    { provide: TokenService.MY_PIPE_TOKEN, useClass: MyPipe }
  ]
})
export class AppModule { }

In the component, use the service to get the right token:

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular';

  constructor(private injector:Injector, private tokenService: TokenService){    
    let myInterface = injector.get(tokenService.getToken('myPipe'));
    myInterface.transform('test');    
  }  
}

Here's a stackblitz showing the updated example.

Upvotes: 1

Related Questions