Home > Back-end >  Angular force pipe transform from within pipe
Angular force pipe transform from within pipe

Time:06-21

Suppose I have my own pipe which looks like this (dummy example)

@Pipe({ name: 'myPipe' })
export class MyPipe implements PipeTransform  {
  private lastKey: string;

  constructor(private myService: MyService) {
    myService.onSomeVariableChange.subscribe((r) => {
      console.log('now i should be transformed again');
    });
  }

  transform(value: any, ...args: any[]) {
    return `${value} ${this.myService.someVariable}`;
  }
}

HTML

<span> {{ 'SomeText' | myPipe }} </span>

I simply return the input with a suffix which is variable. The pipe knows the variable has been changed through the event onSomeVariableChange. The Angular framework should now call transform again.

But since my pipe is pure (and I really don't want it to be impure) and since my input does not change (only an external variable), the transform is not automatically called.

How can I, from within my pipe, force this method to be called? Note that this is a DUMMY EXAMPLE. The real scenario is a lot more complex, so the ideal solution would not be to circumvent this non-existing scenario. The ideal solution would be a way to force transform to be called again.

CodePudding user response:

If the pipe is impure it will update on every change detection cycle - but you could try triggering change detection yourself only when the data updates e.g

constructor(private myService: MyService, cd: ChangeDetectorRef) {
    myService.onSomeVariableChange.subscribe((r) => {
      console.log('now i should be transformed again');
      cd.detectChanges();
    });
  }

I haven't tested this, so not fully sure if it will run the pipe transform again - you may also need to add in cd.markForCheck()

CodePudding user response:

I wouldn't use pipe here, instead, i would use a custom directive like this:

import { Directive, ElementRef, Input } from '@angular/core';

@Directive({
  selector: '[appMyMagicDir]'
})
export class MyMagicDirDirective {

  @Input() appMyMagicDir: string;
  constructor(private elementRef: ElementRef, private myService: MyService) {
    myService.onSomeVariableChange.subscribe(res => {
      elementRef.nativeElement.innerHTML = `${appMyMagicDir}${res}`
    } )
   }

}

then on your element just apply the directive like this:

<span [appMyMagicDir]="someTextVar"></span>

or alternatively and probably simpler -

<span>{{SomeTextVar}}{{myService.onSomeVariableChange | async}}</span>
  • Related