Angular Material Dialogs & Routing Configuration Management
One of the most popular UI component libraries to use with Angular is Angular Material. The library is created and supported by the core angular team, and is a great example of Angular best practices.
Angular Material dialogs work well and look great – however, I’ve always found the typical implementation to be less than ideal. In the documented implementation, all dialog configuration and execution is done from within its parent component. In this blog, I highlight issues with this configuration and demonstrate how dialog management can be achieved entirely inside your application’s routing configuration, like the rest of our components.
Managing Dialog Open/Close States in a Component Method
Here is a typical class method within a parent component for managing a dialog (DialogOverviewExampleDialog
is the component containing our dialog content in this example).
The main issue I see with this: dialog configuration settings (such as component and width) are coupled to the parent component. What if we want to use this dialog and its settings in multiple components? We would either have to say goodbye to having a DRY application, or move this implementation into something that multiple components can reference.
Triggering Dialog Open/Close States using the Application URL
Now we’ve seen how to open/close a dialog from a parent component. This method could simply be called from a button as-is, but what if we want to use the application URL to open the dialog? We would do something like this in the parent component’s ngOnInit()
lifecycle method:
We had to leave our existing dialog management code there, and add 2 angular lifecycle hooks that we weren’t using otherwise. This component’s responsibility has grown considerably from displaying a simple UI with a button – it is now responsible for responding to routing events and managing dialog state.
A better way?
Why should this component care about the dialog state at all? Especially if we are using routing to trigger our dialog – this definitely belongs somewhere else. One option would be to move the dialog and routing logic into a service that gets injected into this component. This would separate the code a little bit, but we are still managing this in a place that’s less than ideal – buried inside a component’s folder.
What if we could manage this in our router config? Most angular apps have a routing configuration file defined at the app level – and a dialog really is just another component that we may even want to route to.
For comedic effect, here is what our parent component looks like when we move all the dialog and routing logic out of it:
And of course, that logic is moved to the routing configuration:
And there you have it! A very centralized configuration for your dialog.
You may notice here that the resolve
property has { dlgRef: DialogResolverService }
– this is the Angular Resolver that handles the logic for reading the settings we provide inside the dlg
property within the config. The actual inner-workings of DialogResolverService
is outside the scope of this post, but fear not – I’ve published an npm package named ng-dialog-router. Add this library to your angular project, and you will be able to import DialogResolverService
like any other angular service.
Running npm install ng-dialog-router --save
will add it to any of your projects
I would also welcome the developer community to submit feature requests, bug reports and code contributions on GitHub!