How to use Bootstrap Modals in Angular in separate components

As many might have experienced, there are some controls from Bootstrap that cannot be easily used in Angular and that's why a good solution is: ng-Bootstrap.

npm install --save @ng-bootstrap/ng-bootstrap

However, not all controls are so easy to use and one complex situation happens, when you want to split Modals into multiple components. The regular Modal looks like this:

HTML Code:

<a (click)="openModal(contentModal)" class="nav-link">Open modal</a>

<ng-template #contentModal let-c="close" let-d="dismiss">
<div class="modal-header">
<h4 class="modal-title" id="modal-primary-title">Title</h4>
<button type="button" class="close" aria-label="Close" (click)="d('Cross click')">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body centered">
<!--Body-->
</div>
</ng-template>

TypeScript code:

openModal(contentModal) {
this.modalService.open(contentModal);
}

And it's perfectly fine if you have one or two Modals and they don't have any logic behind, besides popping up as in an About Modal (Figure 1), but what if you have 3+ Modals with full logic?

Figure 1. Modal.

Many times, these are business requirements and this could create a big mess in your code. The previous solution is not feasible at all in this case. And let's not talk about scalability or many other examples related.

After many attempts, I designed a solution that helped split the Modals into independent components.

The first step is to create your new component:

ng generate component ModalComponent

After, register your Modal in the entryComponents section of your app.module.ts:

entryComponents: [
ModalComponent,
],

Next, copy your old Modal to your new component and remove these 2 lines:

<ng-template #contentModal let-c="close" let-d="dismiss">
</ng-template>

It should look like this:

<div class="modal-header">
<h4 class="modal-title" id="modal-primary-title">Title</h4>
<button type="button" class="close" aria-label="Close" (click)="d('Cross click')">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body centered">
<!--Body-->
</div>

Now, it comes a small change in the logic of the click event and how to call it:

This is the new HTML code:

<a class="nav-link" (click)="openModal()">About</a>

This is the new TypeScript event:
 
openModal() {
//Here you define the name of your component
this.modalService.open(ModalComponent);
//This section is if you want to have any variable to initialize
//compConst.componentInstance.weight = undefined;
}

Also, in your new Component, you need to add change your constructor and add an instance of NgbActiveModal.

constructor(public activeModal: NgbActiveModal) { }

Another important change is in the logic of closing the modal, it needs to be changed to this:

<button type="button" class="close" aria-label="Close"
(click)="activeModal.dismiss('Cross click')">
<span aria-hidden="true">&times;</span>
</button>

You need to change the old: (click)="d('Cross click')" to (click)="activeModal.dismiss('Cross click')"

And with all these changes it will work like charm. I got some inspiration from here:

Comments