Search code examples
angularconditional-statementsangular-pipe

How to add pipes conditionally and dynamically in Angular?


I have multiple pipes and want to add one or more pipes based on a condition to my input element.

It must be check whether the input element (this) has a certain style (this.styles) and based on that style, a pipe must be added to the input element.

So if the style is ReverseString the pipe reverseStr has to be added to the input element.

I created the pipes, and the pipes work when I add it like (see reverseStr):

<input type="text"
    #formItem
    [name]="id"
    [id]="id"
    class="form-control"
    [ngModel]="value | reverseStr"
    (blur)="change.emit(formItem.value)"/>

But how can I add the pipes conditionally in Angular?

I know it's possible in the HTML by adding something like:

[ngModel]="styles.includes('ReverseString') ? (value | SomePipe) : (value | pipe2)"

But this not the most elegant way I think and if I have multiple input components, I need to change it each time

I created a function like:

addPipe() {
const mapping: any = {
    ReverseString: 'reverseStr',
    LowerCase: 'lowerCase',
    UpperCase: 'upperCase',
};

this.styles.forEach((style : any) => {
    const pipes = mapping[style];
    if (pipes) {
        // How can I add the pipes now dynamically? 
    }
});

}

But I don't know how to add the pipe dynamically to the input field.

How to add pipes conditionally and dynamically in Angular?


Solution

  • In order to use dynamic Pipes with input, you can just bind ngModel to setters and getters of the component. Here's how you can do that:

    1. Bind text input ngModel via Setters and Getters

    2. Check for the specific condition on input and use the pipe if evaluates to true

     // component.ts  
    
     private _value;
    
      get value() {
        if(this.nameInput) {
          const inputClasses = this.nameInput.nativeElement.getAttribute('class');
    
          if(inputClasses.indexOf('reverse') !== -1) {
            return (new ReverseStrPipe).transform(this._value);
          } 
        }
        return this._value;
      }
    
      set value(val) {
        this._value = val;
      }
    

    And

    // component.html
    <input type="text"
     #nameInput
    [(ngModel)]="value"/>
    

    Here's the stackblitz example