November 25, 2021

Angular - Using Takeuntil RxJS Operator in Base Class

In the last post , we have seen how to use takeuntil operator to automatically unsubscribe from an observable. takeuntil operator makes it easier to manage the control to unsubscribe from multiple observables.

In that exmaple we have implemented the takeuntil operator in a single component. If you need to implement the same technique in multiple components then you have to repeat the same logic in every component.

In this post we will see how we can implement takeUntil operator in a base class, so that we dont have to repeat the similar code in multiple components.

Here is the code for base class:

import { Subject } from 'rxjs';
import { Component, OnDestroy } from '@angular/core';


@Component({
    template: ''
})
export abstract class BaseComponent implements OnDestroy {

protected componentDestroyed$ = new Subject();

    constructor() { }

    ngOnDestroy() {
        this.componentDestroyed$.next();
        this.componentDestroyed$.complete();
    }
}

And the ChildComponent inheriting the BaseComponent class defined above.

import { Component, OnInit, OnDestroy } from '@angular/core';
import { takeUntil } from 'rxjs/operators';
import { Service1 } from 'Service1';
import { Service2 } from 'Service2';
import { BaseComponent } from 'src/app/models/base-component.model';

@Component({ ... })
export class ChildComponent extends BaseComponent implements OnInit  {

  constructor(private myservice1: Service1, private myservice2: Service2) {}

  ngOnInit() {
    
    this.myservice1.getData()
    .pipe(takeUntil(this.componentDestroyed$)) //componentDestroyed$ is defined in BaseComponent
    .subscribe(({data}) => {
      console.log(data);
    });
	
    this.myservice2.getData()
    .pipe(takeUntil(this.componentDestroyed$))
    .subscribe(({data}) => {
      console.log(data);
    });	
  }
 
 }

Note that, we don't need to implment OnDestroy (ngOnDestroy handler) in ChildComponent to call the next() and complete() methods for subject componentDestroyed$, because we have already defined this in the BaseComponent.

References:

Related Post(s):

November 4, 2021

Angular - Using Takeuntil RxJS Operator

In the last post , we have seen different types of observable. Observable is basically a container which produces asynchronous stream of data, and emit values over time. We have to subscribe to an observable in order to consume or receive data. But you have to be careful with observables as it may leads to memory leaks and affect the application performance. To avoid this issue, one approach is to keep the reference at the time of subscription and unsubscribe from the observable by using the same reference when you no longer need to receive observable's data stream.

Lets see the example code:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';
import { Service1 } from 'Service1';
import { Service2 } from 'Service2';

@Component({ ... })
export class AppComponent implements OnInit, OnDestroy {
  mySubscription1: Subscription;
  mySubscription2: Subscription;

  constructor(private myservice1: Service1, private myservice2: Service2) {}

  ngOnInit() {
    
    this.mySubscription1 = this.myservice1.getData()
    .subscribe(({data}) => {
      console.log(data);
    });
	
    this.mySubscription2 = this.myservice2.getData()
    .subscribe(({data}) => {
      console.log(data);
    });
	
  }
 
  ngOnDestroy() {
    this.mySubscription1.unsubscribe();
    this.mySubscription2.unsubscribe();
  }
 
 }

In this code snippet, we have two services to consume Service1 and Service2. In ngOnInit handler, we maintained the subscription references for both the services in two different variables mySubscription1 and mySubscription2. Then in the ngOnDestroy handler, we are using the same reference variables to unsubscribe from the observable.

The above code works perfectly, but it would be cumbersome to maintain in long term when you have more number of subscriptions which makes you to keep the references for each subscription and then unsubscribe from each one in ngOnDestroy handler.

A better approach is to use takeUntil operator from RxJS library, it is used to automatically unsubscribe from an observable. takeUntil refelects the source Observable. It also monitors a second Observable (the notifier) that you provide. If the notifier emits a value, the output Observable stops reflecting the source Observable and completes itself.

Here is the same exmaple, this time unsubscribe using takeUntil operator.

import { Component, OnInit, OnDestroy } from '@angular/core';

import { Subject, interval } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Service1 } from 'Service1';
import { Service2 } from 'Service2';

@Component({ ... })
export class AppComponent implements OnInit, OnDestroy {
  destroy$: Subject = new Subject();

  constructor(private myservice1: Service1, private myservice2: Service2) {}

  ngOnInit() {

    this.myservice1.getData()
    .pipe(takeUntil(this.destroy$))
    .subscribe(({data}) => {
      console.log(data);
    });
	
    this.myservice2.getData()
    .pipe(takeUntil(this.destroy$))
    .subscribe(({data}) => {
      console.log(data);
    });
  }

  ngOnDestroy() {
    this.destroy$.next(true);
    this.destroy$.unsubscribe();
    
    ////some people prefer to call complete() on destroy$ here, instead of unsubscribe()
    //this.destroy$.complete();
  }
} 

This code snippet also behaves the same as before, but its easier to manage when you have more number of subscriptions. In ngOnDestroy handler, we have called the unsubscribe() method, some people may prefer to call complete() method instead. But in the end it does not make much difference in this context, the purpose here is just to stop receiving more values from this subject.

References: