Вложенные модальные диалоги AngularJS

Я портирую большое бизнес-приложение CRUD, созданное с использованием технологии Oracle -forms, в Интернет (HTML5 / AngularJS / RESTful-web-services).

Отчасти способ настройки бизнес-логики зависит от доступности модальных диалоговых окон, показывающих сетки CRUD. Для начала, пользователи ...

  • щелкните по строке сетки
  • введите данные в первое поле строки
  • нажмите ENTER
  • курсор переходит в следующее поле справа
  • и Т. Д.
  • они редактируют другие поля и т. д.
  • они нажимают "сохранить" где-нибудь на странице
  • проверки происходят, веб-сервис называется -> ДАННЫЕ СОХРАНЕНЫ.

Я создал эту часть с помощью ng-grid AngularUI.

На следующем этапе я споткнулся:

  • Вы дважды щелкаете по строке сетки, появляется новое МОДАЛЬНОЕ диалоговое окно, показывающее «детальную сетку».
  • Вы редактируете / удаляете / и т. Д. Все, что угодно в сетке, и вы также можете снова дважды щелкнуть строку сетки, и появится еще один новый МОДАЛЬНЫЙ диалог, показывающий «сетку деталей-деталей». И так далее.

Когда я попробовал это через службу диалога $ Angular UI, я быстро натолкнулся на стены - есть много проблем с вложенным диалогом $ (например, см. эту проблему в репозиториях GitHub), и что гораздо больше беспокоит, так это то, что недавно (2 месяца назад) они решили просто отказаться от старого диалогового окна, потому что в нем было слишком много проблем, и перепишите его с нуля.

Мой вопрос к любым другим разработчикам Angular: как вы справляетесь с вложенными модальными диалогами? Вы используете другие библиотеки - например, диалог jQueryUI? Если да, то как использовать их «угловым способом»? т.е. без смешивания обработки DOM в ваших контроллерах? Я попытался последовать примеру другого SO question, и он действительно работает, но он встраивает HTML-код диалогового окна в часть страницы, что нехорошо (например, представьте, что вам нужно встроить весь HTML-код для вашего диалогового окна справки, отображаемого с помощью F1 («показать диалоговое окно сочетаний клавиш ") во всех частях вашего HTML-шаблона Angular!

Я рассматриваю возможность загрузки шаблонов диалогов (например, диалогового окна Angular UI) через $ http и вставки содержимого через ngInclude, но это будет означать, что мне придется сохранить для них заполнитель в моем DOM ('#dialogPlace' или что-то в этом роде) - и поскольку у меня есть потенциально неограниченная «глубина» вложенности, я боюсь, что мне придется самостоятельно кодировать «обработку стека», полностью добавляя элементы DOM. Бог знает, что это вызовет само по себе ...

Мне очень нравится Angular, но моя проблемная область требует прочного рабочего компонента для вложенных модальных диалогов. Я надеюсь, что кто-то столкнулся с этой проблемой и имеет чистое, похожее на Angular решение ...


person angularJsNewbie    schedule 06.08.2013    source источник


Ответы (3)


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

Это сервис Angular, который я закодировал (код машинописного текста, поэтому он имеет некоторые спецификации типов, но в остальном - чистый Javascript). Поскольку он будет порождать модальные диалоги, я назвал сервис «Платон» :-)

...

export function addNewServices(application:ng.IModule) {
    application.factory('Plato', ['$http', '$compile', function($http, $compile) {
        return {
            showDialog: function(scope, strTile:string, templateUrl:string, dialogOptions, callback) {
                scope.dialogOptions = dialogOptions;
                scope.dialogOptions.callback = callback;
                $http.get(
                    templateUrl,
                    {timeout:globals.timeoutInMs, cache:false}
                ).success(function(response, status, header, config) {
                    var newDialogId = Sprintf.sprintf("npInnerDlg%d", globals.dialogCounter);
                    globals.dialogCounter += 1;
                    var modalEl = angular.element('<div id="' + newDialogId + '">');
                    modalEl.html(response);
                    $('body').append(modalEl);
                    $compile(modalEl)(scope);
                    var component = $('#' + newDialogId);
                    scope.dialogOptions.jquiDialog = component;
                    component.dialog({
                        autoOpen:false,
                        modal:true,
                        title:strTile
                    });
                    component.dialog("open");
                }).error(function(data, status, header, config) {
                    document.body.style.cursor  = 'default';
                    if (status == 406) {
                        console.log("Received 406 for:" + header + " # " + config);
                        alert("Received 406 from web service...");
                    } else {
                        console.log("Status:" + status);
                        console.dir(config);
                        alert("Timed-out waiting for data from server...");
                    }
                });

            }
        };
    }]);
}

... и используйте это так:

Во-первых, вызывающий код, который хочет показать диалог:

var dialogOptions = {
    callback: function() {
        if (dialogOptions.result !== undefined) {
            cust.mncId = dialogOptions.result.whateverYouWant;
        }
    },
    result: {}
};

Plato.showDialog(
    $scope,
    'Choose something...',
    '/static/partials/municipalityLOV.html',
    dialogOptions
}

с частичным шаблоном HTML с использованием контроллеров и директив angular, как обычно:

<div data-ng-controller="controllerMunicipalitiesLOV">
    <div data-ng-grid="..."
    ...

и модальный контроллер диалогового окна с такими обработчиками:

var dialogOptions = $scope.$parent.dialogOptions;
$scope.close = function(result) {
    dialogOptions.result.whatever = ....;
    dialogOptions.jquiDialog.dialog("close");
    dialogOptions.callback();
}; 

Я в основном перехожу к showDialog:

  • область действия вызывающего, где я храню переданные "dialogOptions"
  • заголовок диалога
  • HTML-шаблон диалога
  • "dialogOptions", где вещи передаются в диалог и из него в .result
  • "dialogOptions" также содержит обратный вызов

Дизайн - это, мягко говоря, полный взлом, но он работает: я использую область действия вызывающего для хранения dialogOptions, а внутри контроллера диалогового окна я использую $ scope. $ Parent.dialogOptions, чтобы читать входящие данные от вызывающего, и сохраните любые результаты, которые будет считывать обратный вызов («dialogOptions» действует как мост между двумя областями действия).

По крайней мере, по состоянию на 2013 год / июль, это единственный способ Angular-y, который я нашел / взломал, чтобы создать модальный диалог, который может быть создан вложенным образом (например, контроллер controllerMunicipalitiesLOV, в свою очередь, вызывает showDialog, а другой контроллер вызывает его снова, и т.д).

Хотел бы я знать способ передать "dialogOptions" в качестве дополнительного параметра контроллеру модального диалога - к сожалению, я плохо разбираюсь во внутренностях Angular; любая помощь приветствуется (это сделало бы этот интерфейс намного чище).

Надеюсь, это кому-то поможет.

person angularJsNewbie    schedule 07.08.2013

Мы использовали http://angular-ui.github.io/bootstrap/#/modal для наших модальных окон.

По сути, здесь была указана та же проблема. Большая сетка с данными привязки, кнопка редактирования для отображения модального окна, удаления, сохранения и т. Д.

У вас будет только один модальный div, скрытый на странице, а затем передать модель строк сетки по щелчку (что было проблемой).

e.g.

$scope.editRow = function (model) {
   // do stuff.
};

<span class="icon-edit" ng-click="editRow(model.row)">Edit</span>

Было странно передавать объекты полем через все методы ng-click / controller только для того, чтобы заставить работать модальное окно, но в конце концов это сработало и было СУХОЕ.

Не уверен, что это полезно.

person Christopher Marshall    schedule 06.08.2013
comment
Боюсь, это не так. Видите ли, я уже использую это - для создания модального окна, которое будет редактировать (дважды) нажатую строку. Моя проблема заключалась в том, что происходит, когда необходимо создать ВТОРОЙ модальный (например, двойной щелчок по сетке первого модального окна) ... В любом случае я отвечу ниже, как я с этим справился. - person angularJsNewbie; 07.08.2013

борясь с той же проблемой, я объединил различные части, создав sgDialogService. Это небольшая модульная служба, которая позволяет использовать несколько вложенных диалогов / предупреждений / подтверждения с синтаксисом, аналогичным стандартному диалоговому окну Angular:

var modalInstance = sgDialogService.openModal({
        templateUrl:'sample/dialogContent.html',
        controller:"sampleController",
        data:{fromParent:dialogParam},
         callback: function(result){ $scope.callbackResult=result;}
    });
}

Идея заключалась в том, чтобы

  • Используйте единый шаблон для всех диалогов (основанный на начальной загрузке)
  • Избегайте любых соединений с другими, кроме Angular и стандартным Javascript
  • Создавайте и компилируйте внутренние представления динамически с помощью сервисов $ controller и $ compile.
  • Разрешить использование диалогового окна (с или) без создания новых областей
  • Наконец, перетащите диалоговое окно (ничего странного, но кажется серьезной проблемой в Интернете.

Как можно скорее выложу версию на github ... нужно только добавить модульные тесты

Изменить 1

Настройте репозиторий на github: sgDialogService

person Kendar    schedule 20.04.2015