2

Hey I have a problem with share operator. When I use async pipe with data$ and totalElements$ my http request executes twice. I wish it would execute only once. I tried to use shareReplay istead and It did not work as well.

filters$: BehaviorSubject<any> = ...
...

getComplaints() {
  return this.filters$.pipe(
    flatMap(filters => {
      this.loading = true;
      return this.complaintService
        .getComplaints$(filters)
        .pipe(
          finalize(() => this.loading = false),
          share()
        );
      })
    );
 }

this.data$ = this.getComplaints().pipe(map(value => value.pageItems));
this.totalElements$ = this.getComplaints().pipe(map(value => value.totalItems));

1 Answers1

2

For share to work you have to create only one observable (so don't use a function) and put the operator on the outer observable. You'll probably want to use shareReplay so that late subscribers get the latest value.

this.complaints$ = this.filters$.pipe(
  flatMap(filters => {
    this.loading = true;
    return this.complaintService
      .getComplaints$(filters)
      .pipe(
        finalize(() => this.loading = false),
      );
    }),
  shareReplay(1)
);

this.data$ = this.complaints$.pipe(map(value => value.pageItems));
this.totalElements$ = this.complaints$.pipe(map(value => value.totalItems));
frido
  • 13,065
  • 5
  • 42
  • 56
  • 2 additions: `this.loading = true`should be moved to a tap. The `finalize` part should also be moved to the outer stream. – MoxxiManagarm Oct 22 '20 at 12:28
  • @MoxxiManagarm `finalize` on the outer stream wouldn't make much sense as the outer stream (this.filters$) is not intended to complete. Only the inner http request completes. – frido Oct 22 '20 at 12:34
  • You are right, but maybe a second tap is the better choice then. – MoxxiManagarm Oct 22 '20 at 12:35
  • Thank you for your reply. I also tried to use tap to set loading as false in outer observable it works as well. In fact finalize used with inner Observable works fine. – Paweł Ostromecki Oct 22 '20 at 12:55