I am working on a fairly complex AngularJS web application and keep failing to implement a working modal / routing mechanism which meet my requirements.
Situation
My application has (simplified) the following entities:
- Customers (has 0 or more Contacts)
- Orders (has exactly 1 Customer)
- Contacts (belong to exactly 1 Customer)
During the creating of a new order an existing customer can be selected, or a new customer can be created. In the creation process of the customer, optionally a new contact can be created.
UI / UX solutions
I've looked at several ways to correctly represent this functionality in a "non-cluttering" and mobile friendly way. First I tried to stay away from modals or popups completely and tried to create several Angular directives to be shown dynamically in the page, but this soon got way too complex. The creation of a new customer exists of multiple UI-states and some substates (tabs) and has fairly complex logic in it.
Then I looked at using separate browser tabs and communicate between them using localStorage. However this approach seemed fragile and also not really common for a user. Besides, the user should continue working in the new tab until finished, and only then be able to return to the previous tab. This is not possible using separate browser tabs.
I've looked at Javascript browser popups, but I don't like that direction either.
From a users point of view, I think the best way was to use a Modal dialog to follow the UI flow:
UI flow
+----------+ +------------+ +-----------+
|New Order | - Opens modal -> |New Customer| - Opens modal -> |New Contact|
+----------+ +------------+ +-----------+
^ | ^ |
| OK | OK
| Closes modal and | | Closes modal and |
| selects new customer | | selects new contact |
+----<-----<-------<-----<---+ +----<-----<-------<-----<----+
Note: the New Customer and New Contact states are also states on itself which can be opened in a regular window.
I have created Angular-UI-Router routes as:
- New Order: app.orders.new
- New Customer: app.customers.new
- New Contact: app.contacts.new
Development
To support the multiple modal architecture I've tried several things:
- Using Angular UI Bootstrap Modal
- Using the UI-Router-Extras way using own built Modal windows
Some important aspects to keep in mind:
- I do not need direct URL's to point directly to a modal window. The URL can stay in the "New Customer"-state.
- The behavior should be Modal, so not able to work on the parent window.
- It should be able to open and show multiple states after each other (for instance a wizard in one Modal)
- Multiple modals that are opened in a certain order should be closed the same order. (Last in, First out)
1. Using Angular UI Bootstrap Modal This way seemed promising. I've created a separate routing which use the some controllers and views of the regular routes:
- Modal.Customers.New
- Modal.Contacts.New
But unfortunately I struggle to open more modals inside the modal and keep state of the previous modal. I've used UI-Router-Extras Sticky States to keep the background state. However as UI-Router-Extras states, Sticky States only works when every state has it's own ui-view. A ui-view should be declared beforehand. This is not possible, because in theory a user can open an unlimited amount of nested modals in my application.
2. Using the UI-Router-Extras way using own built Modal windows
I've tried creating a simple modal in stead of the Angular UI Modal using the simple Modal example of UI-Router-Extras as in: http://plnkr.co/edit/qgt0RkEnXDPDTdMJPIfy?p=info
But unfortunately I have the same problem as with option 1. The problem is the states and routing gets too complex when modals are nested.
Solution
I am really struggling about what is the best approach now. I am thinking about showing a Modal overlay window with an iframe in it which open a seperate UI-Router route like: Modal.Customers.New, which shows only the contents of the application (not the menu bars, etc).
When using iframes I am able to keep the separate route and states info available on the parent window and the iframe. I need to perform some custom javascript to support scaling the iframes to the right format, but that is acceptable.
But it still feels like a "hacked" solution.
I would love to hear your solutions and insights.