Communication between two Components with Subject In Angular

Introduction

When we have to do pass data between independent components which are not parent or child, or not present in the same feature module or in the same nested tree then we will use RxJS subjects and observables for communication.  
A subject is also observable in RxJS. A subject is a producer and a consumer both in RxJS. It can act as an observer as well as an observable. It can hold data as well as emit the data at the same time. The subject is also called a different multicast observable which can do multicasting to the subscribers of the object. The subject implements the observer interface. So it has methods like next(), error(), complete() and unsubscribe().

The two methods which we will use during communication are as follows:
  • Subject.next() - Using the next() method we can send messages through subjects or to an observable and this data will be sent to all the subscribers of the subject or observables.
  • Observable.subscribe() - This method is used to subscribe to the messages which are sent to the observable.

Auth Service To Send Data From One Component To Another

Now we have a service that will send data from any component to another component. We can subscribe to data in any component using this service. We will create a subject in this service using the new Subject() method as follows:

import { Injectable } from '@angular/core';
import { Subject, Observable} from 'rxjs';

export class AuthService {
  prefChangedSubject = new Subject();

  sendPerf(){
     this.prefChangedSubject.next();
  }

  getPerf():Observable<any>{
     return this.prefChangedSubject.asObservable();
  }
}

User Profile Component That Sends Data

Now we will go to the component which sends data to another component. Here in this component whenever the user will save the preference object, we need to send data to another component. So as soon as the user will save the preference object we will call the sendPerf() method of AuthService. 

import { Component, OnInit, Inject } from '@angular/core';
import { AuthService } from '../../services/auth/auth.service';
import { UtilityService } from '../../services/utility-service/utility.service';
import { Location } from '@angular/common';
import { Router } from '@angular/router';
import { Subject } from 'rxjs';

@Component({
  selector: 'app-user-profile',
  template: `<button click="" color="primary" onsubmitpreferences="">SAVE</button>`,
  styleUrls: ['./user-profile.component.scss'],
  providers: [AppDatePipe]
})
export class UserProfileComponent{
  constructor(public _authService: AuthService){}
  async onSubmitPreferences() {
    try {
      if (await this._userSrv.saveUserPref({ dateFormat: this.dateFormat, timeFormat: this.timeFormat })) {
        this._utilsSrv.showToastrSuccess("Success", "Preference saved");
        await this.authSrv.loadPreferences();
        this.authSrv.sendPref(); // Using AuthService to send the notification that preference object has changed
      }
    } catch (e) {
      console.error(e);
      this._utilsSrv.showToastrSuccess("Error", "Error on preference save");
    }
  }
}

Network Component That Receives Data

Now to receive the data, we will go to another component and subscribe to the observable to let this component know that the preference object is changed.

import { Component, OnInit, ViewEncapsulation, NgZone } from '@angular/core';
import { AuthService } from '../../../../../services/auth/auth.service';
import { Observable } from 'rxjs';


@Component({
  selector: 'app-network-user-view',
  templateUrl: './network-user-view.component.html',
  styleUrls: ['./network-user-view.component.scss'],
  encapsulation: ViewEncapsulation.None,
})
export class NetworkUserViewComponent implements OnInit {
 constructor(public _authService: AuthService) {

   this._authService.getPref.subscribe((val) => {  // Subscribing to the observable
     console.log(val); 
    });
}

Comments