LppEdd
LppEdd

Reputation: 21114

Angular Routing and RxJs subscription sharing

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

Answers (1)

dcg
dcg

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

Related Questions