angular assign different observable to template with async based on condition (any memory leak ?)

485 Views Asked by At

I need to render data from different ngrx stores based on some flag. Both stores gives same type of data.

Approach 1

<ng-contaier *ngIf="flag$ | async; else anotherStoreData">
    <ng-container *ngIf="store1$ | async as store1">
        <div>{{ store1?.prop1 }}</div>
        <div>{{ store1?.prop2 }}</div>
    </ng-container>
</ng-contaier>
<ng-template #anotherStoreData>
    <ng-container *ngIf="store2$ | async as store2">
        <div>{{ store2?.prop1 }}</div>
        <div>{{ store2?.prop2 }}</div>
    </ng-container>
</ng-template>

flag$: Observable<boolean>
store1$: Observable<Store>
store2$: Observable<Store>
ngInit() {
    flag$ = streamService.userNewStore();
    store1$ = this.store.select(<someselector1>);
    store2$ = this.store.select(<someselector2>);
}

Approach 2

<ng-container *ngIf="store$ | async as store">
    <div>{{ store?.prop1 }}</div>
    <div>{{ store?.prop2 }}</div>
</ng-container>


store$: Observable<Store>
ngInit() {
    streamService.userNewStore()
    .pipe(takeUntil(this.ngUnsubscribe))
    .subscribe((flag) => {
        store$ = flag ? this.store.select(<someselector1>) : this.store.select(<someselector2>);
    });
}

In Approach1 I am duplicating template, which is fine for small template - but if it is big then i am thinking about Approach 2.

In Approach2 streamService can change the flag at any time, in that case what will happen to the previous subscription in the template with async pipe. Will it lead any memory leak?

Is there any other alternatives that I can use, please suggest.

2

There are 2 best solutions below

1
On BEST ANSWER

Having just checked the source code for the Async pipe, it appears that it will unsubscribe if the Observable changes.

You can see this in line 100 of the file:

if (obj !== this._obj) {
  this._dispose();
  return this.transform(obj as any);
}

If the value being passed in is not the one currently held in memory, it calls this.dispose, which in turn unsubscribes.

With that in mind, I would definitely prefer the 2nd approach

1
On

You can use the flag$ observable in a conditional operator to determine the data source:

<ng-container *ngIf="((flag$ | async) ? store1$ : store2$) | async as store">
  <div>{{ store?.prop1 }}</div>
  <div>{{ store?.prop2 }}</div>
</ng-container>  

See this stackblitz for a demo.