Two ways of using AsyncPipe programmatically

Two ways of using AsyncPipe programmatically

What is AsyncPipe?

AsyncPipe is an angular pipe that helps you resolve an asynchronous value(like an observable or a promise) to a primitive one.

Common use cases of using AsyncPipe:

Being a pipe it’s mostly used on HTML.

Do I need to subscribe/unsubscribe when I use the AsyncPipe on HTML?

No, the implementation of AsyncPipe will take care of subscribing and unsubscribing.

How can I use AsyncPipe programmatically in my custom pipes?

Here you can find two ways of using AsyncPipe in your custom pipes:

1. Providing AsyncPipe and ChangeDetectorRef to Dependancy Injection (DI) in your module

You might think that it will just work if you let Dependancy Injection (DI) do the work for you:

@Pipe({ name: "my_async_pipe" })
export class MyAsyncPipe implements PipeTransform {
  constructor(private asyncPipe: AsyncPipe) {}
  transform(value: any): any {
      return this.asyncPipe.transform(value);
  }
}

Above code will not work and will throw an error like:

ERROR NullInjectorError: StaticInjectorError(AppModule)[ErrorAsyncPipe -> AsyncPipe]: 
  StaticInjectorError(Platform: core)[ErrorAsyncPipe -> AsyncPipe]: 
    NullInjectorError: No provider for AsyncPipe!

Hmmm seams like AsyncPipe has not be added to providers array, let’s fix it:

  • Go to app.module.ts
  • Add providers: [AsyncPipe]
  • reload
ERROR NullInjectorError: StaticInjectorError(AppModule)[AsyncPipe -> ChangeDetectorRef]: 
  StaticInjectorError(Platform: core)[AsyncPipe -> ChangeDetectorRef]: 
    NullInjectorError: No provider for ChangeDetectorRef!

Another injector not provided, let’s repeat the steps above, but this time add ChangeDetectorRef as Provider:

  • Go to app.module.ts
  • This time add providers: [AsyncPipe, ChangeDetectorRef as Provider]
  • reload

Success, AsyncPipe has been successfully provided for your custom Pipe.

2. Creating a new AsyncPipe instance

@Pipe({ name: "cdr_async_pipe" })
export class CdrAsyncPipe implements PipeTransform {
  private asyncPipe: AsyncPipe;
  constructor(private cdr: ChangeDetectorRef) {
    this.asyncPipe = new AsyncPipe(this.cdr);
  }
  transform(value: any): any {
    return this.asyncPipe.transform(value);
  }

  ngOnDestroy() {
    this.asyncPipe.ngOnDestroy();
  }
}

Using:

constructor(private cdr: ChangeDetectorRef) {
   this.asyncPipe = new AsyncPipe(this.cdr);
 }

We are manually creating an instance of AsyncPipe by passing the ChangeDetectorRef as argument. If you do create your own AsyncPipe manually then please don’t forget to call ngOnDestroy() lifecycle method.

Which is the best way to use AsyncPipe programmatically in your custom pipes?

In my opinion the second one is the best because DI will not create two instances of ChangeDetectionRef thus no errors like this._ref.markForChek() is not a function will be thrown as ChangeDetectionRef will be created with one of the classes that extends it.

In the next articles we will look at why when we declare ChangeDetectionRef as a provider we get the error this._ref.markForChek() is not a function.

Live example on codesandbox

Follow me on twitter

Related Posts