0
votes

I have 2 components and a service which provides an observable. Both components are lazy loaded with there modules.

service:

this.filteredBookings$ = this._filteredBookings
  .asObservable()
  .pipe(
    tap(s => {
      console.log(s, 'activity');
      return s;
    })
  );

I have added tap here to see any subscription activity.

component 1:

this.bookings$ = this._bookingService.filteredBookings$;

this.sum$ = this.bookings$.pipe(
  map(bookings => bookings
    .map(booking => booking.value)
    .reduce((total, value) => total + value, 0)
  )
);

component 1 template:

<ion-list *ngIf="bookings$ | async; let bookings; else loading">
    ...
    <ion-label slot="end" text-right>
        <ion-text color="medium"><b>{{ sum$ | async }}</b></ion-text>
    </ion-label>
</ion-list>
...

component 2:

this.bookings$ = this._bookingService.filteredBookings$;

I want to prevent unecessary subscriptions. When I understand it correctly the two observables in component 1 subscribe into observable provided by service. And also the async pipes in component 1 template subscribe into this observable. So there are 4 subscriptions / 3 unecessary ones?

To prevent the unecessary ones I found share().

this.filteredBookings$ = this._filteredBookings
  .asObservable()
  .pipe(
    share()
  );

I think don't need sharereplay because _filteredBookings is an BehaviorSubject which always caches the last value.

The docs say:

"As long as there is at least one Subscriber this Observable will be subscribed and emitting data. When all subscribers have unsubscribed it will unsubscribe from the source Observable."

So when I switch route and load component 2 I fear that observable in service is canceled? Because component 1 observables unsubscribe (async pipe handles unsubscribe?) before component 2 can subscribe?

How can I handle that?

1

1 Answers

0
votes

I've done it in the service like this:

private productsUrl = 'api/products';
private products: IProduct[];

private selectedProductSource = new BehaviorSubject<IProduct | null>(null);
selectedProductChanges$ = this.selectedProductSource.asObservable();

constructor(private http: HttpClient) { }

changeSelectedProduct(selectedProduct: IProduct | null): void {
    this.selectedProductSource.next(selectedProduct);
}

getProducts(): Observable<IProduct[]> {
    if (this.products) {
        return of(this.products);
    }
    return this.http.get<IProduct[]>(this.productsUrl)
                    .pipe(
                        tap(data => console.log(JSON.stringify(data))),
                        tap(data => this.products = data),
                        catchError(this.handleError)
                    );
}

Here is my example: https://github.com/DeborahK/Angular-Communication/tree/master/APM-Final

I don't understand the issue with "prevent unnecessary subscriptions"?

If you want a more formal pattern, you could check out NgRx. I have an example of that here: https://github.com/DeborahK/Angular-NgRx-GettingStarted