angularjsmodal-dialogangular-ui-routerangular-ui-router-extras

Angular modals (ui-router) and general modal architecture concepts


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:

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:

Development

To support the multiple modal architecture I've tried several things:

  1. Using Angular UI Bootstrap Modal
  2. Using the UI-Router-Extras way using own built Modal windows

Some important aspects to keep in mind:

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:

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.


Solution

  • Eventually I went for a combination of using an iframe with Angular UI Modals. This approach gave me complete flexibility in using complicated routes in my App and the Modal screens of Angular UI automatically resize the iframe on different screen resolutions.

    I have created routes for all states used in Modals with the prefix: modal. in stead of app. This way I could only use the "content" subview of the page to show inside the Modal and still have full re-usability of the original controllers and views.

    The only tricky bit was when multiple nested Modals are opened. There I had to check if I was in a Modal or in a regular state. This was pretty easy using the state name:

    IsModal() {
        return this.$state.current.name.indexOf("modal") == 0;
    }
    

    On the root frame (the non-modal view) I collected all opened Angular UI Modals in an array and checked on opening a new modal if the Modal was at the root of the views (non-modal). If not, I traversed up the iframe to the parent scope using:

    var parentScopeModalService = (<any>parent).angular.element(window.frameElement).scope().MyModalService;
    

    This actually worked pretty nice because all iframes are on the same domain.