Playing with dialogs and ng-templates

In this post, I want to explain our experience working with ng-templates inside our modal dialogs, which has been the brief path that we have traveled to get here and what conclusions we draw. It really is not a big change, it does not imply much more code lines and maybe it helps you to improve your modal dialogs.

In this post, I want to explain our experience working with ng-templates inside our modal dialogs, which has been the short path that we have traveled to get here and what conclusions we draw. It really is not a significant change, it does not imply much more code lines, and maybe it helps you to improve your modal dialogs.

In one of our projects (Empresaula), we have some actions that require a modal dialog to improve the usability of our application. For example, the typical alert message: "Are you sure that you want to delete this document?". Until now, for these cases, we used a MatDialog service from Angular Material. We developed a new dialog component for each new requirement. We don't have a considerable number of different dialogs, so it wasn't a priority to improve these components. However, we decided to play with ng-templates, learn a little more about them, and develop a common dialog component to rule them all.

Requirements for our new dialog component:

We want a simple component, no logic, no complexity and easy to maintain.

We want to create different dialogs easily and quickly.

We want a component that helps us to sustain the style for all the modal dialogs.

Label + buttons array

The first approach was a component that accepted a label text for the header, and an array of buttons for the actions. When the dialog was closed, it returned a value corresponding to the clicked button. For each button we needed to define:

label: Button text.

value: The value of the response when the dialog is closed.

cssClass: The class name to know which CSS rules to apply to it (Optional)

Then inside our common component with a ngFor we rendered all the buttons. And here you have the content of our first dialog component:

We already had our common dialog component, but it was not a right solution:

It scales poorly: What happens if some modal needs to render an input of type text? Adding a buttonType in each button will solve it, but for every new requirement, we would need to add logic to our component. Add complexity to the component is the main point that we want to avoid.

Requires a lot of code to generate buttons: To render the buttons list, it's needed to set a lot of data (label, value, cssClass, buttonType in a future, etc.). At empresaula, we have some components that can open five types of a modal dialog, each type with different buttons.

It's not useful for every case: In some dialogs, we render an entire form inside the dialog, with different steps. How is it supposed to build a form using our array buttons variable?

Is ng-templates the right solution?

Yes! Using ng-templates we have removed all the logic from the dialog component, we can render anything inside the dialog, and building extra common components we can maintain the style of the dialogs. Also, we have some extra advantages. Let's take a look.

Generating the content using ng-templates implies that you can control the dialog component from the component that opens it.

The main difference in this approach is that the onDispatchAction is defined where the common dialog is opened, not inside the common dialog component. It seems a small difference, but it has exciting connotations.

The dialog does not even have an action to close itself, so we don't need to subscribe to the function which opens the dialog.

Additionally, by linking it with the utilities that ng-templates give us, we realized the power that our new component had. We can change the content of the modal at any time during the process. For example, we can dispatch an action from the store, change the template to show a loader while the action is processed, and when we get a response from the store we can choose if we close the dialog or we show some advice content. So we have defined two actions at dialogs service to change the header and the template when it's necessary setHeaderText and setTemplate.

// Change the header of the dialogthis.dialog.setHeaderText('New header')// Change the content of the dialogthis.dialog.setTemplate(this.userLoadingActions)// Finally close the dialogconst{ activity }=this.dialog.context // Get context before closethis.dialog.close()