Reputation: 21114
Edit: apparently the shareReplay
approach works fine too. I don't understand why however, given the description of the operator. If someone is so kind to explain why, it will be much appreciated.
I currently have a Component
, managed via routing, with a template that looks like
<app-one [attr]="entity$ | async"></app-one>
<app-two
[attrOne]="(entity$ | async)?.id"
[attrTwo]="(entity$ | async)?.name"
></app-two>
The Component
code is
export class EntityComponent implements OnInit {
entity$: Observable<Entity>;
...
ngOnInit() {
this.entity$ = this.route.paramMap.pipe(
map(params => params.get('entityId')),
mergeMap(entityId => this.service.getEntity(entityId))
);
}
Being that I use the async
pipe three times, the service.getEntity
is called three times (I can see three HTTP calls).
How can I mitigate this problem?
Is adding shareReplay(1)
this.entity$ = this.route.paramMap.pipe(
map(params => params.get('entityId')),
mergeMap(entityId => this.service.getEntity(entityId)),
shareReplay(1)
);
an acceptable solution? I don't think so, as it will mess up routing.
Edit: my components are all OnPush
, and subscribing and storing the result as a class property would mean having to detectChanges
, which I don't like at all.
Upvotes: 1
Views: 437
Reputation: 4219
I think you could wrap your two components with a ng-container
applying the async
pipe and store the result in a variable and then use that in the components, something like:
<ng-container *ngIf="entity$ | async as entity"
<app-one [attr]="entity"></app-one>
<app-two
[attrOne]="entity?.id"
[attrTwo]="entity?.name"
></app-two>
</ng-container>
Update What I mean is that you are able to do something like:
this.entity$ = new Observable<Entity>(observer => {
observer.next(null);
this.route.paramMap.pipe(
map(params => params.get('entityId')),
mergeMap(entityId => this.service.getEntity(entityId)),
).subscribe(e => {
observer.next(e);
observer.complete();
}, () => {
observer.complete();
});
});
Hope it helps!
Upvotes: 2