Create custom pipe that is async by itself

Several commenters pointed out (rightfully so) that this violates SRP and might hurt readability. But even though that’ll make me reconsider whether I want this, I still for sure wanted to know how to do it if you want it. I found two solutions (with help from commenters, again).

Composition (not recommended)

Create your own internal AsyncPipe and use it. Here’s a base setup that should work:

@Pipe({ name: 'apiText', pure: false })
export class ApiTextPipe implements PipeTransform, OnDestroy {
  private asyncPipe: AsyncPipe;

  constructor(private myApiService: MyApiService, private injector: Injector) {
    this.asyncPipe = new AsyncPipe(injector.get(ChangeDetectorRef));
  }

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

  transform(key: string): string {
    return this.asyncPipe.transform(this.myApiService.getText(key));
  }
}

In addition to the abovementioned downsides (noted by commenters), I see other issues:

  • If ever the AsyncPipe changes, e.g. it starts implementing OnInit, then our own pipe also needs to change. And you will likely miss this. It’s not good that our pipe’s implementation is coupled in this way to the AsyncPipe.

  • I couldn’t seem to get AsyncPipe injected because it relies on the special ChangeDetectorRef, so I used this suggested approach asking it directly from the injector. (There’s likely a better way to do this, but I’m not digging further for now…)

Inheritance (not recommended)

You could also try to extends AsyncPipe in your own pipe, but that route lies even more awkward code that tightly couples your pipe to the async pipe. Some problems with that approach when I tried it:

  • You again need a ChangeDetectorRef to pass to the super(...) call
  • You need to tightly couple to the signature of the transform method from the AsyncPipe
  • The transform gets super complicated as it no longer just takes a string (see the previous point)
  • Unknown to me if this properly makes Angular call the super class’s ngOnDestroy method

Plus whatever else I forgot. The code I had felt so icky that it doesn’t seem wise to even share it.

Duplicate the Source (not recommended?)

As one of the commenters suggested, the source for AsyncPipe is open. So you could take that and build your own pipe from that.

This is not a wise decision in my opinion and I’d recommend against it, but it is the solution recommended by the Angular team on GitHub.

Stick with double pipes (the only decent option?)

So doing {{'some-key' | apiText | async}} and always using two pipes, seems to be the only somewhat reasonable option currently.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)