I want to write a collapsible component which has an "Expand" button that opens a list of items. This list is created through a web request, and I'm wondering when this request happens - since to my understanding the async
pipe is like a subscription and the ngIf
would cause the component subscribing to be recreated, I would expect the value of the request to only be available once, however it is created each time I 'show' the expander.
Inside my AppComponent
I have this logic:
data$ = of('expensive data from server').pipe(
take(1),
tap(() => console.log('data from server emit!')),
// shareReplay(1),
finalize(() => console.log('complete!'))
);
showSon = true;
The template is like this:
<button (click)="showSon=!showSon">Click me!</button>
<p *ngIf="showSon">
<ng-container *ngIf="data$ | async as data">
<div>{{data}}</div>
</ng-container>
</p>
My understanding is that since the observable is created via of
, that it should fire its value once and then complete, confirmed by the console logs. However I'm surprised that every time I show the element inside the ngIf
, I still get a value even though async
is now subscribing to a completed observable that is not a ReplaySubject
.
I think using shareReplay(1)
would solve the issue of making multiple web requests, but I still don't understand how the single-use observable is repeatedly available whenever the template inside the ngIf
is recreated.
MikeOne's comment is correct.
Everytime the If is true, the element gets recreated.. so the async pipe re-subscribes to the data$ observable causing it to emit again..
Your solution is also correct, to use
shareReplay(1)
as you've mentioned.