Note this is simplified question of Angular template binding with Observable async pipe issue
template:
<div>{{foo()$ | async}}</div>
source code:
import { Component } from "@angular/core";
import { BehaviorSubject, of, Observable } from "rxjs";
import { tap, delay, map, switchMap, concatMap } from "rxjs/operators";
@Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
private index = 0;
foo$(): Observable<any> {
console.log("aaa")
return of("Delayed");
}
}
The above code works as expected:

However if I added .pipe(delay(1)) to the foo$():
foo$(): Observable<any> {
return of("Delayed").pipe(delay(1));
}
it won't work and keep "aaa" in the console log.
See https://stackblitz.com/edit/angular-qbhkg3
A method called from the template, is called every change detection cycle. Because you are using the async pipe, the change detection is triggered with every emit. So basically you are creating an infinite loop and that's why it will never show a value, because the change detection never finishes:
foo$()foo$() creates a -new- observable and delays the emitasync pipefoo$() from the template, and we're back to step 2It's not really clear what you are trying to achieve, but I don't think you should return Observables from methods to be consumed in templates. These should be readonly class field:
readonly foo$ = of("Delayed").pipe(delay(1));
It is however possible to use a method, but you have to make sure this method returns the same Observable:
private readonly _foo$: Observable<any> = of("Delayed").pipe(delay(1));
foo$(): Observable<any> {
console.log('here');
return this._foo$;
}
example
Because the observable object stays the same (===), it's all good in the hood. Once you add a pipe to the Observable you create a new reference and you come back into the infinite loop.
The reason it does not reach the infinite loop if you just return of('delayed'), is because the Observable is not asynchronous this way. The Observable will return a value immediately to the async pipe, and when the async pipe calls detectChanges() nothing really happens, because it's still in the same cycle as the change detection cycle which triggered the foo$() template call.
I see you also linked a previous question you posted which involves the use of a decorator. You should change that decorator to a class field decorator, and you can then do the following:
@NeedsElement(sp(115621), ap(116215))
readonly insuredType$!: Observable<string>;
I think I can think of a way to make it work with a method call, but before I dive into that, I first want to know why you want it to be a method call in the first place
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With