Angular 7/8/9 | Angular EventEmitter and RxJs Subjects Quick Tutorial by Example

Data communication between components siblings or from Parent to child or vise-versa is possible by using many ways in Angular applications.

Sometimes we may need to pass data or any information to parent component from any of its child components in its hierarchy. For example, we have messages component which shows unread messages, now if we want to display the count on the header component.

In that case, we have two options available to do so. The EventEmitter available in angular core package and RxJS Subject provides observable which can be used to emit values to other components.

Using Angular Core’s EventEmitter

The EventEmitter class which is a part of @angular/core package can emit the data to we can subscribe to in parent component.

This is a traditional old approach we used to use in Angular for passing on data or emit to parents and can observe the change using the subscribe method.

Using RxJs subject

The RxJS Subjects also works in a similar way and implementation is also a way more identical like EventEmitter but they are more preferred.

In subjects, we use the next method to emit values instead of emitting.
The subject is a special kind of observable which is more active as the next method is exposed directly to emit values for observable.

In our quick example, we will discuss both methods for which we will create a new child component SendMessageComponent which will emit string message to the app’s main component for which we also need a service.

Let’s quickly implement one by one…

Create a new Service

To implement in a better way we will use a service that is a good practice we can follow in a real application.

Run following ng generate command to create a new service in the services folder:

$ ng g service services/send-message

Above command will create following service:

// send-message.service.ts
import { Injectable, EventEmitter } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class SendMessageService {

  constructor() { }
  
}

Auto-generated service is already having the providedIn set to 'root'  if you want to set it in app.module.ts file's providers array then it's also fine.

 The EventEmitter method:

To use EventEmitter just create a new instance of it to a variable messageEmitter to keep instance, which will accept String, you can set any type for data you want to emit.

The EventEmitter is available in the angular core package we need to import first.

// send-message.service.ts
import { Injectable, EventEmitter } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class SendMessageService {

  messageEmitter = new EventEmitter<String>(); 

  constructor() { }
}

Emit Value

Now from the SendMessageComponent component we will emit value using the above service.

Add a button with method sendMessage() to send string value using emit method as shown below:

In the send-message.component.html file add button

<button class="btn btn-primary" (click)="sendMessage()">Send Message</button>

 

update the send-message.component.ts file with following code:

// send-message.component.ts
import { Component, OnInit } from '@angular/core';
import { SendMessageService } from 'src/app/services/send-message.service';

@Component({
  selector: 'app-send-message',
  templateUrl: './send-message.component.html',
  styleUrls: ['./send-message.component.css']
})
export class SendMessageComponent implements OnInit {

  constructor(
    private sendMessageService: SendMessageService
  ) { }

  ngOnInit() {
  }

  sendMessage(){
    this.sendMessageService.messageEmitter.emit('Message From Child Component');
  }

}

Get Emitted Values

We are getting the emitted values in app.component.ts file using the service variable messageEmitter which returns an observable.

In the ngOnInit() hook we will put this observable and feed its value in the local variable messageToShow:

// app.component.ts
import { Component, OnInit } from '@angular/core';
import { SendMessageService } from './services/send-message.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
  title = 'angular-eventemitter-and-subject-demo';

  messageToShow:String;

  constructor(
    private sendMessageService: SendMessageService
   ) { }

   ngOnInit(){
    this.sendMessageService.messageEmitter.subscribe(msg=>{
      this.messageToShow = msg;
    })
   }

}

That's it now if users click on Send Message button in child component it will emit the string value using service to app component.

Now we will check how to convert EventEmitter with RxJS Subject.

The Subject Method:

To use Rxjs Subject we only need to make changes at just two places:

1) In the SendMessageService replace

messageEmitter = new EventEmitter<String>();

with

messageEmitter = new Subject<String>();

where we need to import Subject from rxjs:

// send-message.service.ts
import { Injectable, 
 // EventEmitter 
} from '@angular/core';

import { Subject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class SendMessageService {

  //messageEmitter = new EventEmitter<String>();
  messageEmitter = new Subject<String>(); 

  constructor() { }
}

2) In the SendMessageComponent we need to use next() instead of emit():

// send-message.component.ts
import { Component, OnInit } from '@angular/core';
import { SendMessageService } from 'src/app/services/send-message.service';

@Component({
  selector: 'app-send-message',
  templateUrl: './send-message.component.html',
  styleUrls: ['./send-message.component.css']
})
export class SendMessageComponent implements OnInit {

  constructor(
    private sendMessageService: SendMessageService
  ) { }

  ngOnInit() {
  }

  sendMessage(){
    //this.sendMessageService.messageEmitter.emit('Message From Child Component');
    this.sendMessageService.messageEmitter.next('Message From Child Component');
  }

}

That's its that simple 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *