Understanding Multicasting Observables in Angular
Tags: javascript, angular, rxjs
Published: 2020-05-21 19:45:20

---
title: Understanding Multicasting Observables in Angular
published: true
description: How to Multicast Observables in Angular
tags: JavaScript, Angular, RxJS
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/afirzjg1nxospubrhy72.gif
canonical_url: https://jenniferwadella.com/blog/understanding-multicasting-observables-in-angular
---

Many times in Angular application development we'll have an Observable, and want to use the values from that Observable to do different things in the UI. 

Let's imagine we're building this interface that shows information about a fish, and we want to show users a schedule of when that fish is available based on the hemisphere of the world selected. 

![Fish Display UI](https://dev-to-uploads.s3.amazonaws.com/i/afirzjg1nxospubrhy72.gif)

In our component we'll get the response of an HTTP request to the animal crossing API. We're using HTTPClient which returns an Observable. We want to display data from that HTTP request in our UI so a user can see information about the fish, but we also want to display a custom built schedule based on that data and input from something else.  

The API returns an object that looks something like this: 

```json
{
   "id":10,
   "fileName":"killifish",
   "name":{
      "name-en":"killifish",
      ...
   },
   "availability":{
      "month-northern":"4-8",
      "month-southern":"10-2",
      "time":"",
      "isAllDay":true,
      "isAllYear":false,
      "location":"Pond",
      "rarity":"Common"
   },
   "shadow":"Smallest (1)",
   "price":300,
   "priceCj":450,
   "catchPhrase":"I caught a killifish! The streams are safe again.",
   "museumPhrase":"Ah, the magnificent killifish! Did you know there are over 1,000 different species? My own favorite killifish species are the mangrove, which can live on land for weeks, breathing air! And the mummichog, the first fish ever brought to space. I wonder if the killifish you've brought me is related to either those intrepid explorers?",
}
```

We want to get the availability based on the hemisphere(northern or southern) the user cares about, and display the months during which that fish is available, by creating an array like this: 

```typescript
[
   {
      "month":"January",
      "available":false
   },
   {
      "month":"February",
      "available":true
   },
   ...
]
```

We might consider doing something like this (note we are using the Async pipe in our component template to subscribe to `fish$`):

```typescript
// fish.component.ts 

  public fish$: Observable<Fish &{uiSchedule: Schedule}> ;
  public selectedHemi = new BehaviorSubject<'northern' | 'southern'>('northern');
  public displayedSchedule$: Observable<Month[]>;

  constructor(private route: ActivatedRoute, private acnhService: AcnhService) { }

ngOnInit(): void {
    this.fish$ = this.route.paramMap.pipe(
      switchMap((params: ParamMap) => {
        return this.acnhService.getFish(params.get('id')).pipe(map((res: Fish) => {
          return {
            ...res,
            uiSchedule: {
              // mapping function to generate array of months with key of 
              // whether month is available or not
              northern: buildSchedule(res.availability, 'northern'),
              southern: buildSchedule(res.availability, 'southern')
            }
          }
        }));
      }),
    )

    this.displayedSchedule$ = this.selectedHemi.pipe(
      withLatestFrom(this.fish$),
      map(([selectedHemi, fish]) => {
        return fish.uiSchedule[selectedHemi];
      })
    )
  }
```


```html
// fish.component.html 
<mat-card *ngIf="fish$ | async as fish" color="secondary">
  <mat-card-header>
    <mat-card-title>{{fish.name['name-en']}}</mat-card-title>
    <mat-card-subtitle>{{fish.price | currency }}</mat-card-subtitle>
  </mat-card-header>
  <mat-card-content class="row">
    <div>
      <img src="{{fish.imageUrl}}" alt="{{fish.name['name-en']}}">
      <blockquote class="museum-phrase">"{{fish.museumPhrase}}"</blockquote>
    </div>
    <div>
      <mat-button-toggle-group name="hemisphere" [value]="selectedHemi | async" aria-label="Hemisphere" color="primary" (change)="selectedHemi.next($event.value)">
        <mat-button-toggle value="northern">Northern Hemisphere</mat-button-toggle>
        <mat-button-toggle value="southern">Southern Hemisphere</mat-button-toggle>
      </mat-button-toggle-group>
      <div class="table display-availability">
        <div class="month" *ngFor="let month of displayedSchedule$ | async"  [ngClass]="{'available':month.available}">
          {{month.month}}
        </div>
      </div>
      <div *ngIf="fish.availability.isAllDay;else limitedHours">
        <p>The {{fish.name['name-en']}} is available at all times</p>
      </div>
      <ng-template #limitedHours>
        <p>The {{fish.name['name-en']}} is available from {{fish.availability.time}}</p>
      </ng-template>
    </div>
  </mat-card-content>
</mat-card>
```

This will give us a `displayedSchedule$` Observable with an array that displays either the northern or southern hemisphere schedule when the value of `selectedHemi` changes. Again, assume that we're using the Async pipe in our template to subscribe to this Observable because we want the tear down functionality of our Angular component to handle unsubscribing for us. 

But by doing this we're creating an additional subscription to `fish$` when we subscribe to `displayedSchedules`, which means our Observable is being executed twice, quite unnecessarily. Not to mention rude, this awesome developer built a great free API indexing Animal Crossing stuff, and we're thoughtlessly hitting it twice? Ruuuuuude. (ps. how many of ya'll have been doing something like this without even realizing?)

How can we avoid this? 

Instead of an _Observable_, we can use a _Subject_ instead. Subjects can have multiple subscribers and only execute their context once. To convert an Observable to a Subject we can use the [multicast operator](https://rxjs-dev.firebaseapp.com/api/operators/multicast). 

The multicast operator is a bit of a bear to understand - it takes a selector as a parameter and according to the docs returns 

>"An Observable that emits the results of invoking the selector on the
> items emitted by a ConnectableObservable that shares a single
> subscription to the underlying stream." 

A more palatable summary from the docs is 

> "A multicasted Observable uses a Subject under the hood to make multiple Observers see the same Observable execution. Multicast returns an Observable that looks like a normal Observable, but works like a Subject when it comes to subscribing. multicast returns a ConnectableObservable, which is simply an Observable with the connect() method.

> The connect() method is important to determine exactly when the shared Observable execution will start. Because connect() does source.subscribe(subject) under the hood, connect() returns a Subscription, which you can unsubscribe from in order to cancel the shared Observable execution.

So let's pipe the multicast operator to source Observable `fish$` with a new `ReplaySubject` (because we want late subscribers to get the value). 

___

On the Subject of Subjects ...

_subject_ - a special type of Observable that allows values to be multicasted to many Observers

_behaviorSubject_ - a subject that can 'store' a current value that new subscribers will receive

_replaySubject_ - a subject than can send old values to new subscribers
___

 ```typescript
 this.fish$ = this.route.paramMap.pipe(
      switchMap((params: ParamMap) => {
        return this.acnhService.getFish(params.get('id')).pipe(map((res: Fish) => {
          return {
            ...res,
            uiSchedule: {
              northern: buildSchedule(res.availability, 'northern'),
              southern: buildSchedule(res.availability, 'southern')
            }
          }
        }));
      }),
      multicast(new ReplaySubject(1))
    )
``` 

... now we have nothing displaying in our UI? Why? We still have the async pipe subscribing to `fish$`, but `fish$` is now a ConnectableObservable, and we must call the `connect` method on it to trigger our source observables execution. 

```typescript
// RxJS source code

function Multicast() {
   ...
   return <ConnectableObservable<R>> connectable;
}

export class ConnectableObservable<T> extends Observable<T>{
   ...  
   connect(): Subscription {
    let connection = this._connection;
    if (!connection) {
      this._isComplete = false;
      connection = this._connection = new Subscription();
      connection.add(this.source
        .subscribe(new ConnectableSubscriber(this.getSubject(), this)));
      if (connection.closed) {
        this._connection = null;
        connection = Subscription.EMPTY;
      }
    }
    return connection;
  }

  refCount(): Observable<T> {
    return higherOrderRefCount()(this) as Observable<T>;
  }
  ...
}
```


```typescript
this.fish$.connect()
```

However, this means we must also remember to unsubscribe from that subscription created by the connect method, so doesn't that defeat the purpose of using the async pipe? Yep. Boo. BUT, fear not, gentle reader, we can use the `refCount` operator, instead of having to manage the `connect` method ourselves. 

> refCount makes the multicasted Observable automatically start executing when the first subscriber arrives, and stop executing when the last subscriber leaves.

RefCount returns an Observable that keeps track of how many subscribers it has, it will start executing when subscribers is more than 0, and stops when subscribers are 0 again. This means when we use our async pipe on `fish$`, the count will become 1, when we use our async pipe on `displayedSchedule$` the count will become 2 and when our component is destroyed and the async pipes unsubscribe, the count will go back to 0. 
 
Our final code looks something like this

```typescript
    this.fish$ = this.route.paramMap.pipe(
      switchMap((params: ParamMap) => {
        return this.acnhService.getFish(params.get('id')).pipe(map((res: Fish) => {
          return {
            ...res,
            uiSchedule: {
              northern: buildSchedule(res.availability, 'northern'),
              southern: buildSchedule(res.availability, 'southern')
            }
          }
        }));
      }),
      multicast(new ReplaySubject(1)),
      refCount()
    )
```


In summary, when we have an Observable we'd like to use a source for various purposes without executing its context every time, we can use the `multicast` operator to take a Subject and use it to share the source execution of our source Observable. The multicast operator returns a ConnectableObservable type, on which we CAN use the `connect` method to create the subscription to our source Observable(the HTTP request to get a fish). A more manageable approach is to use the refCount operator which will count subscriptions and call the `connect` method to subscribe to the source Observable once the first subscription is created and run tear down logic when the subscription count returns to 0 (AKA all the subscriptions have been unsubscribed).