MCMatan
MCMatan

Reputation: 8863

Call Async functions (Retunes Observable) from HTML template

Data displayed on HTML template is Key form data. Meaning, it needs to be translated. For that purpose, I would like to call an Async function from my template. Tried this, with no success:

Template:

<span class="myClass-rowValue">{{translateServingStyle(size.defaultServingStyle?.surcharge) | async}}</span>

Component ts file:

servingStylesData$: Observable<ServingStyles_servingStyles[]>;

ngOnInit(): void {
    this.servingStylesData$ = of(this._apollo
      .watchQuery<ServingStyles>({
        query: ServingStylesQuery
      }))
      .pipe(
        filter((query) => !!query),
        switchMap((query) => query.valueChanges),
        take(1),
        takeUntil(this._ngOnDestroy),
        map((response) => response.data.servingStyles)
      );
}

translateServingStyle(servingStyleValue: string): Observable<string> {
    return this.servingStylesData$
      .pipe(
        map((servingStyles) => servingStyles
          .filter((servingStyle) => servingStyle.value === servingStyleValue)
          .map((selectedServingStyle) => selectedServingStyle.value)[0]
          )
      );
  }

What is the currect why of doing this?

# Edit

This is making my browser crash. Getting into an endless loop calling translateServingStyle()

I have tried removing my function code, and just returning

of("some string")

and it works fine.

But when referencing a Pipe to a local Variable, this loop happens. Can anyone please explain why?

Upvotes: 3

Views: 3958

Answers (1)

Julien Ambos
Julien Ambos

Reputation: 2098

tl;dr Don't use the async pipe with function calls. This is expensive and long-running and can destroy the user experience or in your case crash your browser: Manage your observables yourself and not with the easy to use async pipe.

If you still want to use the async pipe with a function, you can try using the ChangeDetectionStrategy.OnPush. This comes with other downsides, such as running the change detection manually, e.g. with this.cdr.detectChanges(); and cdr being of type ChangeDetectorRef.


Please be aware of how Angulars Lifecycle system works.

Since evaluated function values do not have an internal reference (which Angular uses to check whether values have changed or need to be updated), they won't be checked by the lifecycle hook ngOnChanges, but rather with ngDoCheck, which runs a lot of times.

This is especially bad with pipes, and the worst with the async pipe. If we call your usage of async pipes expensive and long running, Angular states, that:

An expensive and long-running pipe could destroy the user experience

or in your case crash the browser.

Please find this blog post for further explanation.

Upvotes: 5

Related Questions