NG Bootstrap Modal With Full Typing (ngx-bootstrap-typed-modal)
Tags: angular, programming, typescript, tutorial
Published: 2022-12-05 15:47:19

Few weeks ago I was working on an Angular project and I tried to implement a simple deletion confirmation modal with [ng-bootstrap](https://ng-bootstrap.github.io/#/home) and I was surprised to see that there is no way to keep the modal input and result typed, you are forced to manage `any` types in the modal... I don't want to have to touch any `any` 😛.

This is why I created a simple Angular library ([ngx-bootstrap-typed-modal](https://www.npmjs.com/package/ngx-bootstrap-typed-modal)) that keep typing and provide a simple way to create modals and process its result.

Let's get started!

Demo:
{% embed https://codesandbox.io/embed/ng-bootstrap-modal-with-full-typing-drycmh?expanddevtools=1&view=preview&fontsize=17&hidenavigation=1&module=%2Fsrc%2Fapp%2Fapp.component.ts&theme=dark %}

## Prerequisites

Before you start, you need:
- [Angular 14 ](https://angular.io/)(`ng new my-app`)
- [NG Bootstrap 13](https://ng-bootstrap.github.io/#/home). (`ng add @ng-bootstrap/ng-bootstrap`)

---
Setup
=====

Get the library ([ngx-bootstrap-typed-modal](https://www.npmjs.com/package/ngx-bootstrap-typed-modal))

1. Add `ngx-bootstrap-typed-modal` to package.json
--------------------------------------------------

```
npm i ngx-bootstrap-typed-modal
```

This will add the following line to the "dependencies" section of the app `package.json` file:
```json
"dependencies": {
  ...
  "ngx-bootstrap-typed-modal": "^0.5.2"
}
```

So the `package.json` will look something like this:

![Preview of package.json after library installation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b9oynvtu8duecymjmtgk.png)

2. Add `NgbTypedModalModule` to the app
------------------------------------------


Before using the library, you need to register it to Angular, to do so start by adding the import in `src/app/app.module`:
```ts
import { NgbTypedModalModule } from 'ngx-bootstrap-typed-modal'
```

Then in the `imports` section add:
```ts
imports: [
  ...
  NgbTypedModalModule
],
```

The `app.module` should look something like this:
![Preview of the module.app after adding the import](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nd282o28s19c62s4lsu3.png)

Implementation examples:
- [Hello World Modal](https://github.com/Dymerz/ngx-bootstrap-typed-modal/blob/HEAD/projects/example-app/src/app/modals/hello-world-modal/hello-world-modal.component.ts)
- [Yes No Modal](https://github.com/Dymerz/ngx-bootstrap-typed-modal/blob/HEAD/projects/example-app/src/app/modals/yes-no-modal/yes-no-modal.component.ts)

---
Let's using it!
===============

We will create a basic modal that will say "This is your last chance Neo" and return if the user has clicked on the "Blue pill" or "Red pill" button.

![Preview of the final result of a typed modal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rrxnx755whnx9bl25die.gif)

### Create the component

Let's starting by adding the component that will hold your modal content and behavior:
```bash
ng generate component matrix-modal
```

And go into the `matrix-modal/matrix-modal.component.ts`, it should look like this:
![Preview of the matrix-modal.component.ts](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1ngg6yopnydeb9eezsuz.png)

For now this is a simple component, in the next section we will transform our component to a fully typed modal.

### Create Input and Output types

```ts
// `InputData` type which will describe what the component needs as input for the modal to be opened.
type InputData = {
  name: string
}

// `OutputData` type which will describe what the component needs as output when the modal is closed.
type OutputData = 'blue' | 'red';
```

### Extend the component with `NgbTypedModal`

extend and pass our `InputData` and `OutputData` as arguments.
```ts
export class MatrixModalComponent extends NgbTypedModal<InputData, OutputData> implements OnInit {
  // ...
  constructor() {
    super();
  }
}
```

The component should be like this:
![Preview of the matrix-modal.component.ts after extending](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q74rcn9h6hb708k6eohz.png)

### Add the logic

In the `matrix-modal.component.html` add:
```html
<h4>This is your last chance <b>{{ data.name }}</b></h4>

<div class="modal-footer">
  <button class="btn btn-danger" (click)="onRedPillClicked()">Red Pill 💊</button>
  <button class="btn btn-primary" (click)="onBluePillClicked()">Blue Pill 💊</button>
</div>
```

And in the `matrix-modal.component.ts` add:
```ts
  // ...

  ngOnInit(): void {
    // print to the console data that was passed as input.
    console.log('input', this.data);
  }

  onBluePillClicked(): void {
    // send the 'blue' value and close the modal.
    this.submitData.emit('blue');
  }

  onRedPillClicked(): void {
    // send the 'red' value and close the modal.
    this.submitData.emit('red');
  }
```
> Learn more about [available methods and properties](https://www.npmjs.com/package/ngx-bootstrap-typed-modal#user-content-ngbtypedmodal).

You can see that when calling `this.submitData.emit` you have a fully typed parameters, if you enter something else than the allowed string in the `InputData`, TypeScript will throw us an error!

![Demo of a Typescript error for the output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/18byr28xpp44keykccie.gif)

Now we have a fully configured modal, all we need to do now is implementing it.

---
### And Finally implement the modal

in the `app.component.ts` add:
```ts
  ngOnInit(): void
  {
    // create the modal
    const modalRef = new MatrixModalComponent().make(this.ngModal)
      .setComponent(MatrixModalComponent) // component to place in the modal
      .setTitle('Matrix')                 // set the title
      .setInput({name: 'Neo'})            // pass inputs
      .show()                             // show the modal

    // handle the modal response
    modalRef.result.then(result => {
      // check that the user has not dismissed the modal
      if(!result) {
          console.log('I will wait')
          return;
        }

      if(result === 'blue')
        console.log('You were the chosen one!')

      if(result === 'red')
        console.log('Follow me.')

      // TS error
      if(result === 'green')
        console.log('rabbit hole 🐇')
    })
  }
```

And...
![Demo of typing in the modal result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n4orazqc83pex5316bos.png)

You now have a fully typed modal, congrats!! 🎉

---
Thanks for reading the whole story, if you have any improvements feel free to open a [pull request](https://github.com/Dymerz/ngx-bootstrap-typed-modal/pulls)!