Adonis Js - Events and Mailing Part 2
Tags: adonis, beginners, javascript, node
Published: 2021-10-05 17:00:14

> Curiosity keeps leading us down new paths. ~ Walt Disney

It is often said that in programming there's always more than one way of doing things. The maxim is that to grow we must be open to new ideas...new ways of doing things. 

As developers, we always try to explore different ways of doing things.

In this second piece of implementing events and mailing in Adonis, I'll demonstrate another technique we can use to capture different events in our applications.

A reminder that the entire source code for this project can be found [here](https://github.com/tngeene/adonis-tutorial-fitit).
Let's start.

## Using the built-in Adonis event emitter module

For this guide, we'll use the built-in Event emitter module that comes in AdonisJs. You can peruse the [official event documentation](https://docs.adonisjs.com/guides/events) to have a better understanding of this concept.

We'll implement the same flow we did in our [previous article](https://dev.to/tngeene/events-and-mailing-part-1-2oi1), where the user receives a notification email upon registration to activate their account, so be sure to check it out!

## What is the AdonisJs event module?

According to the adonis documentation, "The AdonisJS event emitter module is built on top of emittery".

[Emittery](https://github.com/sindresorhus/emittery) is a modern async event emitter for node.js.

> Some basic knowledge of the node.js event loop would help you better understand it but is not necessary.

## Usage

    node ace make:prldfile events

This command creates a new events.ts file in the contracts directory. This file is the entry point for all events in our application. Select all options prompted by the CLI.

```typescript
import User from 'App/Models/User'

declare module '@ioc:Adonis/Core/Event' {
  interface EventsList {
    'new:user': { newUser: User }
  }
}

```

The `Event.on` method registers a new event listener. It accepts the name of the event, in our case `new:user`, followed by a method to handle the events as the arguments.

## Listener Classes

Listener classes define the logic for our events. This is similar to the model function we defined in the last post.
Conventionally event listeners are stored inside the app/Listeners directory. However, you can customize the namespace inside the `.adonisrc.json` file.

To make a new event listener class that will handle the emailing, run the following command.

```
node ace make:listener User

```

A new `User.ts` file will be created under the `app/Listeners/` directory. Open the newly created file and paste this code.

```typescript
import Mail from '@ioc:Adonis/Addons/Mail'
import Env from '@ioc:Adonis/Core/Env'
import { EventsList } from '@ioc:Adonis/Core/Event'
import Route from '@ioc:Adonis/Core/Route'

export default class User {
  public async onNewUser({ newUser }: EventsList['new:user']) {
    const appDomain = Env.get('APP_URL')
    const appName = Env.get('APP_NAME')
    const defaultFromEmail = Env.get('DEFAULT_FROM_EMAIL')
    const currentYear = new Date().getFullYear()
    const url = Route.builder()
      .params({ email: newUser.email })
      .prefixUrl(appDomain)
      .makeSigned('verifyEmail', { expiresIn: '24hours' })
    await Mail.send((message) => {
      message
        .from(defaultFromEmail)
        .to(newUser.email)
        .subject('Please verify your email')
        .htmlView('emails/auth/verify', { user: newUser, url, appName, appDomain, currentYear })
    })
  }
}

```

As you can see, the code above is very similar to what we'd defined earlier as the `sendVerificationEmail()` function. For a more detailed explanation, head over to [that article](https://dev.to/tngeene/events-and-mailing-part-1-2oi1) and check out the description.

However, just as a recap, we're defining the mail sending capability and building a URL that will encode our user token. The token expires in 24 hours and is tied down to a named URL, `verifyEmail`. Now, onto the new stuff.

   public async onNewUser({ newUser }: EventsList['new:user'])

We're defining an async function named, `onNewUser` inside the default User class that takes the `newUser` as an argument. The newUser argument is tied to the event we just defined before. There, it'll always ensure that the parameters passed will match the ones defined in the event declaration.

If you wish to pass more than one argument, you can always define them in the `events.ts` file by separating them with semicolons.
```javascript

 'new:user': { newUser: User; <arg2>: <modelName; <arg3>: <modelName;... }

```

Then calling the same arguments on the function declaration

```typescript
public async onNewUser({
newUser,
arg2,
arg3,
....
})

```

Finally, we can emit our event on the authController.

Import the events module

```
import Event from '@ioc:Adonis/Core/Event'

```

Then right below the validation in the register function

```typescript

const data = await request.validate({ schema: validations })
const newUser = await User.create(data)

Event.emit('new:user', {
  newUser,
})

```

We're calling the `new:user` event we defined in the `events.ts` file as this is the event name, the second parameter is the arguments to take.

> Note that the argument names must be named similarly to the arguments we passed to the event declaration. By this I mean that you have to name the variable newUser just as it's declared in the event declaration. The same follows when having multiple arguments.

Now, we'll test the event.

### Testing
> Remember to turn on the development server by running, `node ace serve --watch``

### Registration

![https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oqw6psdvb6m4jd7thi1f.png](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oqw6psdvb6m4jd7thi1f.png)

### Email

![https://dev-to-uploads.s3.amazonaws.com/uploads/articles/seg2tvj2j71lu9teh6jf.png](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/seg2tvj2j71lu9teh6jf.png)

### Account activated

![https://dev-to-uploads.s3.amazonaws.com/uploads/articles/acxn2isxsxr1o7i4srq3.png](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/acxn2isxsxr1o7i4srq3.png)

### Resources

1. The complete source code can be accessed on my [Github profile, here](https://github.com/tngeene/adonis-tutorial-fitit).
2. Frontend code for the email template can be found in this [GitHub gist](https://www.notion.so/78a312be1151c46a994b21c1729cf3d5)
3. [official adonis events documentation](https://docs.adonisjs.com/guides/events)
4. [Node.js event loop](https://blog.logrocket.com/a-complete-guide-to-the-node-js-event-loop/).

### Conclusion

In this article, we've learned another way of working with events in AdonisJs. It's entirely up to you to decide which method best works for you. That being said, always employ the most optimal approach.
If you have any queries, comment and insight, don't hesitate to reach out on my [Twitter](https://twitter.com/Ngeene_kihiu), [personal website](https://tngeeene.com/) or simply by leaving a comment below.

I'll be going over models, migrations, and relationships in my next article. Till then...cheers!