Using a bootstrap modal as a dynamic component
Working in an application involving multiple components under different modules, there are scenarios where in you’d not want to fix another template for a simple functionality like a modal component, let’s say!
For such components, we can actually build a dynamic component where in we would not need to render the template at the build time but as and when required at the runtime.
So, in this blog post, I will be writing about using a bootstrap modal as an info modal entry component for our application.
To start, we will create a regular Angular component using
ng generate component <component-name>
So let us start by creating an Info modal component which we will render only when we require it on an operation in another component.
Assuming that we have set up an Angular application, we will create a component and insert it in the entryComponents array inside NgModule.
The next step is to include the bootstrap modal inside our application. To do that we will install ng-bootstrap as a dependency inside the application.
npm i -- save @ng-bootstrap/ng-bootstrap
You would also need bootstrap 4 CSS in yor app so add that inside the angular.json in the styles array.
Once, this is set up, we can go to the InfoModal component and start implementing the modal.
In the info-modal.component.ts,
The first step is to import NgbModal from ng-bootstrap library
import { NgbActiveModal } from ‘@ng-bootstrap/ng-bootstrap’;
On the info modal view, we want to have something that looks like this:
To have this view, we need two buttons on the info-modal.component.html,
The data for this component comes as an Input from the component that wants to render this component. So on the info-modal.component.ts,
On the click on primary button, we perform some action whereas on the click of the secondary button, we would simply dismiss the modal.
To dismiss the modal, we’d simply use the reference to NgbActiveModal like follows:
To want to perform an operation on the click of the primary button, we would need to emit an event from the info-modal component to the one that renders this component. To do that, we’ll use Output and EventEmitter and emit the event on the click of the primarybutton.
This is the ready info modal component that we want to render from every component wherever and whenever we require it. This should receive the data through Input() and emit the action that should be performed when clicked on the primary button.
Let us render this component in our application now. Remember we have not rendered this component now since we have NOT placed the selector of this component on any template as we always do!
<app-info-modal></app-info-modal>
So instead, we will create the component instance and use it to render the InfoModal component.
Let us render the component now!
I have created a new component, RenderInfoModal, which looks like this:
On the click of Stop editing this text, we want to invoke the InfoModal.
<button (click)=”invokeInfoModal()”>Stop editing the text</button>
Now let us create an instance of this inside the invokeInfoModal method.
Inside the invokeInfoModal method,
we have taken a variable as an instance of NgbModalRef and inside the method, we have created a modalconfig coming from the NgbModalOptions package.
To render the component now, we will use the open method of a modalservice like this:
this.stopEditing= this._modalService.open(InfoModalComponent, modalConfig);
This is the vital thing to understand here:
The stopEditing variable takes the input to render the dynamic component using the open method and specifying the name of the component that is to be loaded and as we have specified in the modalConfig which is this:
const modalConfig: NgbModalOptions = {
windowClass: 'info-modal-sm',
size: 'sm',
ariaLabelledBy: 'info-modal',
centered: true
};
If you look closely at the code inside the modal.d.ts file, you will see how the bootstrap modal component is generated as a dynamic component using the ComponentFactoryResolver, Injector services.
constructor(_moduleCFR: ComponentFactoryResolver, _injector: Injector, _modalStack: NgbModalStack, _config: NgbModalConfig);
When we use _modalservice.open, this does the trick for us and loads the dynamically generated component.
Look at the open method in the modal.d.ts,
To send the data to our dynamic component just like we do property binding, we would use the componentInstance to receive the data in the modalData property of the InfoModal component. Instead of hard coding the data here, I am getting it from a INFO_MODAL_CONSTANT.ts file.
The INFO_MODAL_CONSTANT file contains the template structure for the STOP_EDITING_MODAL_DATA:
Also, to catch the emitted event here inside the rendering component, we would use the componentInstance as:
This should open the modal as well as perform operation with the emitted event.
Now when you click on ‘Yes’, which is the primary button here, it should emit an action to the rendering component that can then perform any action that it needs to, for example, for making an API call, routing to a different view, performing some other action or just dismissing the modal.
This is an example of using this dynamic modal component by the ng-bootstrap library. However, we can create our own dynamic component and render it in our application.
In the next blog post, I will write about creation of a dynamic component, using the ComponentFactoryResolver from ‘@angular/core’ package.
Thank you for reading this blog post and I am very open to feedback. Please let me know on how can it be improved.
THANK YOU!