Угловые модальные окна (ui-router) и общие концепции модальной архитектуры

Я работаю над довольно сложным веб-приложением AngularJS и не могу реализовать работающий механизм модальности/маршрутизации, который соответствует моим требованиям.

Ситуация

Мое приложение имеет (упрощено) следующие сущности:

  • Клиенты (имеет 0 или более контактов)
  • Заказы (имеет ровно 1 клиента)
  • Контакты (принадлежат ровно 1 Заказчику)

При создании нового заказа можно выбрать существующего клиента или создать нового клиента. В процессе создания клиента можно дополнительно создать новый контакт.

UI/UX-решения

Я рассмотрел несколько способов правильного представления этой функциональности в «не загромождающей» и удобной для мобильных устройств форме. Сначала я пытался полностью отказаться от модальных окон и всплывающих окон и попытался создать несколько директив Angular для динамического отображения на странице, но вскоре это стало слишком сложным. Создание нового клиента состоит из нескольких состояний пользовательского интерфейса и некоторых подсостояний (вкладок) и имеет довольно сложную логику.

Затем я рассмотрел использование отдельных вкладок браузера и связь между ними с помощью localStorage. Однако такой подход показался пользователю хрупким и не очень привычным. Кроме того, пользователь должен продолжать работу в новой вкладке до тех пор, пока не закончит работу, и только после этого иметь возможность вернуться на предыдущую вкладку. Это невозможно при использовании отдельных вкладок браузера.

Я просмотрел всплывающие окна браузера Javascript, но мне это направление тоже не нравится.

С точки зрения пользователя, я думаю, что лучшим способом было использовать модальное диалоговое окно, чтобы следовать потоку пользовательского интерфейса:

Поток пользовательского интерфейса

+----------+                   +------------+                  +-----------+
|New Order | - Opens modal ->  |New Customer| - Opens modal -> |New Contact|
+----------+                   +------------+                  +-----------+
      ^                            |   ^                             |
      |                            OK  |                             OK
      |     Closes modal and       |   |      Closes modal and       |
      |    selects new customer    |   |     selects new contact     |
      +----<-----<-------<-----<---+   +----<-----<-------<-----<----+

Примечание: состояния «Новый клиент» и «Новый контакт» также являются состояниями сами по себе, которые можно открыть в обычном окне.

Я создал маршруты Angular-UI-Router как:

  • Новый заказ: app.orders.new
  • Новый клиент: app.customers.new
  • Новый контакт: app.contacts.new

Разработка

Для поддержки множественной модальной архитектуры я пробовал несколько вещей:

  1. Использование Modal Angular UI Bootstrap
  2. Использование способа UI-Router-Extras с использованием собственных встроенных модальных окон

Некоторые важные аспекты, о которых следует помнить:

  • Мне не нужны прямые URL-адреса, чтобы указывать непосредственно на модальное окно. URL-адрес может оставаться в состоянии «Новый клиент».
  • Поведение должно быть модальным, поэтому нельзя работать с родительским окном.
  • Он должен иметь возможность открывать и показывать несколько состояний друг за другом (например, мастер в одном модальном режиме).
  • Несколько модальных окон, которые открываются в определенном порядке, должны быть закрыты в том же порядке. (Последним пришел, первым ушел)

<сильный>1. Использование Modal Angular UI Bootstrap Этот способ казался многообещающим. Я создал отдельную маршрутизацию, в которой используются некоторые контроллеры и представления обычных маршрутов:

  • Модальные.Клиенты.Новые
  • Модальные.Контакты.Новые

Но, к сожалению, я изо всех сил пытаюсь открыть больше модальных окон внутри модального окна и сохранить состояние предыдущего модального окна. Я использовал липкие состояния UI-Router-Extras, чтобы сохранить фоновое состояние. Однако, как указано в UI-Router-Extras, Sticky States работает только тогда, когда каждое состояние имеет собственное представление пользовательского интерфейса. Пользовательский интерфейс должен быть объявлен заранее. Это невозможно, потому что теоретически пользователь может открывать неограниченное количество вложенных модальных окон в моем приложении.

<сильный>2. Используя способ UI-Router-Extras с использованием собственных встроенных модальных окон

Я попытался создать простое модальное окно вместо Angular UI Modal, используя простой модальный пример UI-Router-Extras, например: http://plnkr.co/edit/qgt0RkEnXDPDTdMJPIfy?p=info

Но, к сожалению, у меня та же проблема, что и с вариантом 1. Проблема в том, что состояния и маршрутизация становятся слишком сложными, когда модальные окна вложены друг в друга.

Решение

Я действительно борюсь с тем, что является лучшим подходом сейчас. Я думаю о том, чтобы показать окно наложения Modal с iframe в нем, которое открывает отдельный маршрут UI-Router, например: Modal.Customers.New, который показывает только содержимое приложения (а не строки меню и т. д.).

При использовании iframes я могу сохранить отдельную информацию о маршруте и состояниях, доступную в родительском окне и iframe. Мне нужно выполнить некоторый пользовательский javascript для поддержки масштабирования iframe до нужного формата, но это приемлемо.

Но это все еще похоже на «взломанное» решение.

Я хотел бы услышать ваши решения и идеи.


person Rody van Sambeek    schedule 25.04.2016    source источник


Ответы (1)


В конце концов я выбрал комбинацию использования iframe с Angular UI Modals. Этот подход дал мне полную гибкость в использовании сложных маршрутов в моем приложении, а модальные экраны пользовательского интерфейса Angular автоматически изменяют размер iframe при разных разрешениях экрана.

Я создал маршруты для всех состояний, используемых в модальных окнах, с префиксом: модальный. вместо приложения. Таким образом, я мог использовать только подпредставление «контент» страницы для отображения внутри модального окна и при этом иметь возможность полного повторного использования исходных контроллеров и представлений.

Единственная сложность заключалась в том, что было открыто несколько вложенных модальных окон. Там я должен был проверить, был ли я в модальном или в обычном состоянии. Это было довольно просто, используя имя состояния:

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

В корневом фрейме (немодальное представление) я собрал все открытые модальные окна Angular UI в массив и проверил при открытии нового модального окна, находится ли модальное в корне представлений (немодальное). Если нет, я прошел iframe до родительской области, используя:

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

На самом деле это сработало очень хорошо, потому что все фреймы находятся в одном домене.

person Rody van Sambeek    schedule 11.05.2016