Many times we need to decouple different parts of our application and still want communication between these parts. Events come in quite handy in such situations. In this post, we will look at how to use the NestJS Event Emitter.

NestJS has its own Event Emitter package. It provides a simple observer implementation. This allows us to subscribe and listen for various events.

So let’s dive right in.

1 – Installing the NestJS Event Emitter package

The first step is to actually install the required package in our project.

This can be done using the below command.

$ npm i --save @nestjs/event-emitter

Once the installation is successful, we need to import the package in the app.module.ts of our project. See below example:

import { Module } from '@nestjs/common';
import { EventEmitterModule } from '@nestjs/event-emitter';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { EventDemo } from './event.demo';

@Module({
  imports: [EventEmitterModule.forRoot()],
  controllers: [AppController],
  providers: [AppService, EventDemo],
})
export class AppModule {}

Here, we import the EventEmitter in the imports array. The forRoot() call initializes the event emitter. It also registers any declarative event listeners that might exist within the the application. If you wish to know more about modules, please read this detailed post about NestJS Module System.

info

INFO

Registration of the Event Emitter occurs when the onApplicationBootstrap lifecycle hook occurs. By the time this hook triggers, all modules have been loaded in the context.

We can also configure the EventEmitter instance by passing a configuration object to the .forRoot() function. See below:

EventEmitterModule.forRoot({
  // set this to `true` to use wildcards
  wildcard: false,
  // the delimiter used to segment namespaces
  delimiter: '.',
  // set this to `true` if you want to emit the newListener event
  newListener: false,
  // set this to `true` if you want to emit the removeListener event
  removeListener: false,
  // the maximum amount of listeners that can be assigned to an event
  maxListeners: 10,
  // show event name in memory leak message when more than maximum amount of listeners is assigned
  verboseMemoryLeak: false,
  // disable throwing uncaughtException if an error event is emitted and it has no listeners
  ignoreErrors: false,
});

2 – Dispatching Event using Event Emitter

To dispatch an event, we simply need to use the EventEmitter2 instance. We can do so by the constructor dependency injection.

See below code:

import { Injectable } from "@nestjs/common";
import { EventEmitter2 } from "@nestjs/event-emitter";

@Injectable()
export class EventDemo {
    constructor(private eventEmitter: EventEmitter2){}

    emitEvent() {
        this.eventEmitter.emit('msg.sent', 'Hello World')
    }
}

We create a class known as EventDemo and create a method emitEvent(). Basically, this method uses the EventEmitter instance and emits a simple Hello World message. Here, the first argument i.e. msg.sent is the event name. We can use this name to listen to events. The second argument is the payload. Here, we simply have a string. However, it can also be another object.

3 – Listening to the Event

The next step is to implement an appropriate listener for this event. We will create another method in the same EventDemo class.

import { Injectable } from "@nestjs/common";
import { EventEmitter2, OnEvent } from "@nestjs/event-emitter";

@Injectable()
export class EventDemo {
    constructor(private eventEmitter: EventEmitter2){}

    emitEvent() {
        this.eventEmitter.emit('msg.sent', 'Hello World')
    }

    @OnEvent('msg.sent')
    listentToEvent(msg: string) {
        console.log('Message Received: ', msg)
    }
}

We annotate the method using the @OnEvent() decorator. Basically, this decorator receives the event name as argument. In this case it is msg.sent. Then, it simply prints the message to the console.

If we want a certain category of events to be handled by this listener, we can use wildcard as below:

@OnEvent('msg.*')
listentToEvent(msg: string) {
   console.log('Message Received: ', msg)
}

This will match all events starting with msg. If we wish a particular listener to catch all events, we can use something like below:

@OnEvent('*.*')
listentToEvent(msg: string) {
   console.log('Message Received: ', msg)
}

4 – Triggering the Event

For this example, we will trigger the event from the controller class as below.

import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
import { EventDemo } from './event.demo';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService, private readonly eventDemo: EventDemo) {}

  @Get()
  sayHello() {
    this.eventDemo.emitEvent();
  }
}

Basically, this is a simple controller that uses the EventDemo instance to call the emitEvent() method. If you wish to know more about controllers, you can read this detailed post about NestJS Controllers.

Conclusion

With this, we have learn how to use NestJS Event Emitter. We implemented a basic event emitter and listener and also looked at the various approaches to configure listeners.

If you have any comments or queries on this topic, please feel free to write in the comments section below.


Saurabh Dashora

Saurabh is a Software Architect with over 12 years of experience. He has worked on large-scale distributed systems across various domains and organizations. He is also a passionate Technical Writer and loves sharing knowledge in the community.

0 Comments

Leave a Reply

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