Я провел некоторое исследование по этому вопросу как в SO, так и в Google. Но ни один из ответов не служит моей цели.
У меня модальный вид в HTML, который я использую для отображения всплывающих уведомлений в моем приложении. Я хочу показать несколько кнопок ("ОК", "Отмена", "Вход" и т.д.) В div
модуле, который я динамически передаю как объект JS. Название кнопки - это ключ, а функция обратного вызова - это значение.
Примеры:
{
"Login": function(){....}
}
{
"OK": function(){...},
"Cancel": function(){...}
}
Теперь я showPopup(message, buttonMap)
такие объекты методу showPopup(message, buttonMap)
в контроллере всплывающего showPopup(message, buttonMap)
у меня есть.
message
является отображаемым сообщением во всплывающем buttonMap
а buttonMap
является объектом в примерах.
контроллер:
angular.module('core').controller('PopupController', ['$rootScope', 'LogService', 'MessageHandlerService',
function ($rootScope, LogService, MessageHandlerService) {
var ctrl = this;
ctrl.buttonMap = {};
ctrl.btnWidth = 100;
$rootScope.$on('popup', showPopup);
function showPopup (event, message, buttonMap) {
$('#genericModalDialog .popup-content p').html(message);
ctrl.buttonMap = buttonMap;
var numberOfButtons = Object.keys(buttonMap).length;
ctrl.btnWidth = (100 - numberOfButtons*2)/numberOfButtons;
$("#genericModalDialog").modal('show');
}
ctrl.callbackFor = function callbackFor(key) {
ctrl.buttonMap[key].call(null);
};
}
]);
Обслуживание:
angular.module('core').service('PopupService', ['$rootScope', 'LogService', 'CacheService', 'MessageHandlerService',
function ($rootScope, LogService) {
this.isPopupShown = function (){
return $("#genericModalDialog").hasClass('in');
}
this.showPopup = function (message, btnMap){
$rootScope.$broadcast('popup', message, btnMap);
}
this.closePopup = function (){
$("#genericModalDialog").modal('hide');
}
}
]);
Посмотреть:
<div ng-controller="PopupController as popupCtrl" class="modal fade" id="genericModalDialog" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="vertical-alignment-helper">
<div class="modal-dialog vertical-align-center" style="width:94%;">
<div class="modal-content">
<div class="modal-body">
<br/><br/>
<div class="popup-content">
<p align="center"></p><br/>
<div class="popup-action">
<button type="button" class="btn" style="width:{{popupCtrl.btnWidth}}%; margin:1%" ng-repeat="(buttonName, callBack) in popupCtrl.buttonMap" ng-click="popupCtrl.callbackFor(buttonName)">{{buttonName}}</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Поскольку я не хочу создавать экземпляр PopupController
в каждом другом контроллере/службе, я написал службу под названием PopupService
которая имеет метод, который может вызывать и будет $broadcast
$rootscope
события под названием "popup"
на $rootscope
и я обрабатываю это событие в PopupController
. В этом случае все срабатывает и работает нормально. Единственная проблема, с которой я сталкиваюсь, - это задержка в отображении всплывающего окна в пользовательском интерфейсе, я вижу сообщение, как только отображается всплывающее окно, но рендеринг кнопок очень медленный (примерно 3 секунды), это связано с загрузкой какой-либо другой веб-страницы на заднем фоне.
Когда я искал информацию об этой проблеме в Интернете, я также обнаружил, что эта общая настройка может быть изменена на директиву и рендеринг динамического содержимого (в этом случае всплывающее окно и кнопки на нем.) Можно поместить в функцию ссылки этой директивы.
Другой подход, который я видел, заключался в прямом обращении с манипуляциями DOM в службе, что, конечно, не очень хорошо.
Я пропустил какой-либо другой подход или решение этой проблемы?
Все, что я хочу знать, - это то, что было бы наилучшим образом, чтобы справиться с этой ситуацией, которая является программным и конструктивным.
Если я не понимаю, сообщите мне. Я попробую снова объяснить проблему.
Директива будет гораздо лучшим выбором, чем манипуляция DOM. Кроме того, вам следует рассмотреть возможность изменения использования диалога jQuery в https://angular-ui.github.io/bootstrap/#/modal.
Вот пример того, как это можно сделать:
1) Создайте директиву
app.directive('myModal', function() {
return {
restrict: 'E',
scope: {
items: "=",
message: "="
},
replace: true,
templateUrl: "directiveTemplate.html",
controller: function($scope, $uibModal, $log) {
$scope.open = function(size) {
var modalInstance = $uibModal.open({
animation: $scope.animationsEnabled,
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
size: size,
resolve: {
items: function() {
return $scope.items;
},
message: function() {
return $scope.message;
}
}
});
modalInstance.result.then(function(selectedItem) {
$scope.button = selectedItem.name;
$scope[selectedItem.callback](selectedItem.name);
});
};
}
}
});
2) Создайте директиву modalInstance
app.controller('ModalInstanceCtrl', function($scope, $uibModalInstance, items, message) {
$scope.items = items;
$scope.message = message;
$scope.close = function(item) {
$uibModalInstance.close(item);
};
});
3) создать директивный шаблон directiveTemplate.html
<div>
{{buttonClicked}}
<br> {{button}}
<button type="button" class="btn btn-default" ng-click="open('sm')">{{message}}</button>
</div>
4) создать всплывающий шаблон 'myModalContent.html'
{{message}}
<button ng-repeat="item in items" type="button" class="btn btn-default" ng-click="close(item)">{{item.name}}</button>
5) определите контроллер, где у вас будет список кнопок и сообщения, которые будут отображаться во всплывающем окне (для демонстрационной цели здесь представлены два разных списка элементов и два сообщения)
app.controller('ModalDemoCtrl', function($scope) {
$scope.message = "modal 1";
$scope.items = [{
name: 'item1',
callback: "test1"
}, {
name: 'item2',
callback: "test2"
}, {
name: 'item3',
callback: "test3"
}];
$scope.message2 = "modal 12222";
$scope.items2 = [{
name: 'item1222',
callback: "test1"
}, {
name: 'item2222',
callback: "test2"
}, {
name: 'item3222',
callback: "test3"
}];
$scope.test1 = function(message) {
$scope.buttonClicked = "clicked test1";
}
$scope.test2 = function(message) {
$scope.buttonClicked = "clicked test2";
}
$scope.test3 = function(message) {
$scope.buttonClicked = "clicked test3";
}
});
и для того, чтобы вам была нужна директива:
<div ng-controller="ModalDemoCtrl">
<my-modal items="items" message="message"></my-modal>
</br>
<my-modal items="items2" message="message2"></my-modal>
</div>
Если у вас есть директива, доступная из разных экземпляров углового приложения, чем просто вставлять директивное приложение в необходимое (убедитесь, что директива и модальный экземпляр имеют свой собственный определенный модуль ex: var app = angular.module('myPopupDynamicModule', ['ngAnimate', 'ui.bootstrap']);
и это тот, который будет использоваться для инъекций в другие модули, следующие этому примеру: var app2 = angular.module('ui.bootstrap.demo', ['ngAnimate', 'ui.bootstrap', 'myPopupDynamicModule']);
)