ventana small modal framework examples docs create crear ionic-framework

ionic-framework - small - ventana modal en ionic



Pase un controlador a $ ionicModal (6)

Me pregunto si puede pasar un controlador al servicio $ ionicModal. Algo como.

$ionicModal.fromTemplateUrl(''templates/login.html'', { scope: $scope, controller: ''MyModalCotroller'' })

Un pequeño contexto: me gustaría tener un modal que se distribuye en la aplicación y no quiero repetir todos los métodos (ocultar, mostrar, botones dentro del modal) en cada controlador y me gustaría eliminar los métodos del '' Controlador principal para mantener las cosas limpias. Esto encapsularía la funcionalidad del modal.

Hay alguna forma de hacer esto.? Gracias


Basado en esta pregunta y otras necesidades, creo un servicio que puede ser útil.

De todos modos use el código CodePen, este actualizado, mejorado y pone a disposición el parámetro ''options'' de $ ionicModal.

Ver esta publicación: Servicio modal iónico o ver en operación: CodePen

(function () { ''use strict''; var serviceId = ''appModalService''; angular.module(''app'').factory(serviceId, [ ''$ionicModal'', ''$rootScope'', ''$q'', ''$injector'', ''$controller'', appModalService ]); function appModalService($ionicModal, $rootScope, $q, $injector, $controller) { return { show: show } function show(templateUrl, controller, parameters) { // Grab the injector and create a new scope var deferred = $q.defer(), ctrlInstance, modalScope = $rootScope.$new(), thisScopeId = modalScope.$id; $ionicModal.fromTemplateUrl(templateUrl, { scope: modalScope, animation: ''slide-in-up'' }).then(function (modal) { modalScope.modal = modal; modalScope.openModal = function () { modalScope.modal.show(); }; modalScope.closeModal = function (result) { deferred.resolve(result); modalScope.modal.hide(); }; modalScope.$on(''modal.hidden'', function (thisModal) { if (thisModal.currentScope) { var modalScopeId = thisModal.currentScope.$id; if (thisScopeId === modalScopeId) { deferred.resolve(null); _cleanup(thisModal.currentScope); } } }); // Invoke the controller var locals = { ''$scope'': modalScope, ''parameters'': parameters }; var ctrlEval = _evalController(controller); ctrlInstance = $controller(controller, locals); if (ctrlEval.isControllerAs) { ctrlInstance.openModal = modalScope.openModal; ctrlInstance.closeModal = modalScope.closeModal; } modalScope.modal.show(); }, function (err) { deferred.reject(err); }); return deferred.promise; } function _cleanup(scope) { scope.$destroy(); if (scope.modal) { scope.modal.remove(); } } function _evalController(ctrlName) { var result = { isControllerAs: false, controllerName: '''', propName: '''' }; var fragments = (ctrlName || '''').trim().split(//s+/); result.isControllerAs = fragments.length === 3 && (fragments[1] || '''').toLowerCase() === ''as''; if (result.isControllerAs) { result.controllerName = fragments[0]; result.propName = fragments[2]; } else { result.controllerName = ctrlName; } return result; } } // end })();

Uso:

appModalService .show(''<templateUrl>'', ''<controllerName> or <controllerName as ..>'', <parameters obj>) .then(function(result) { // result from modal controller: $scope.closeModal(result) or <as name here>.closeModal(result) [Only on template] }, function(err) { // error });

Puede usar otro servicio para centralizar la configuración de todos los modales:

angular.module(''app'') .factory(''myModals'', [''appModalService'', function (appModalService){ var service = { showLogin: showLogin, showEditUser: showEditUser }; function showLogin(userInfo){ // return promise resolved by ''$scope.closeModal(data)'' // Use: // myModals.showLogin(userParameters) // get this inject ''parameters'' on ''loginModalCtrl'' // .then(function (result) { // // result from closeModal parameter // }); return appModalService.show(''templates/modals/login.html'', ''loginModalCtrl as vm'', userInfo) // or not ''as controller'' // return appModalService.show(''templates/modals/login.html'', ''loginModalCtrl'', userInfo) } function showEditUser(address){ // return appModalService.... } }]);


Cree una directiva para usar dentro del modal y dentro de la directiva puede asignarle al modal su propio controlador y alcance. Si alguien quiere un código de ejemplo, puedo poner algo.


Estaba buscando una manera simple de conectar un controlador a una instancia modal y administrar todos los modales con un solo servicio. Además, quería que el modal tuviese su propio alcance infantil aislado. No estaba satisfecho con el uso de ng-controller y encontré otras respuestas demasiado complicadas hasta el punto en que podía perder fácilmente el alcance del alcance y terminar con dependencias circulares o no identificables. Creé el siguiente servicio para mis propósitos.

Puede pasar un parámetro parentScope opcional para asignar explícitamente un ámbito principal al ámbito modal creado.

Podrías modificar fácilmente el método instantiateModal para aceptar $ ionicModal options como argumento, simplemente no tenía la necesidad de hacerlo.

Por cierto, estoy usando el babel-loader de Webpack para la transpilación y el cargador de html para cargar las plantillas. Pero, en su forma más simple, es solo un servicio básico.

/** * nvModals * @description A modal manager. Attaches a specified controller to an $ionicModal instance. */ import myModalTemplate from ''../common/modals/my-modal.html''; import otherModalTemplate from ''../common/modals/other-modal.html''; let nvModals = function ( $rootScope, $controller, $ionicModal ) { var _self = this; _self.methods = { /** * Instantiate and show a modal */ showMyModal: (parentScope) => { var parentScope = parentScope || null; _self.methods.instantiateModal(''MyModalController'', myModalTemplate, parentScope) .show(); }, /** * Instantiate and show another modal */ showOtherModal: (parentScope) => { var parentScope = parentScope || null; _self.methods.instantiateModal(''OtherModalController'', otherModalTemplate, parentScope) .show(); }, /** * Instantiate a new modal instance * * @param {object} controller Controller for your modal * @param {string} template Template string * @param {object} parentScope Optional parent scope for the modal scope * @return {object} Modal instance */ instantiateModal: (controller, template, parentScope) => { var modalScope; if(parentScope) { modalScope = $rootScope.$new(false, parentScope); } else { modalScope = $rootScope.$new(false); } $controller(controller, { ''$scope'': modalScope }); modalScope.modal = $ionicModal.fromTemplate(template, { scope: modalScope, animation: ''slide-in-up'' }); modalScope.$on(''modal.hidden'', (evt) => { evt.targetScope.$destroy(); if (evt.targetScope.modal) { evt.targetScope.modal.remove(); } }); modalScope.hideModal = function () { modalScope.modal.hide(); }; return modalScope.modal; } }; return _self.methods; }; nvModals.$inject = [ ''$rootScope'', ''$controller'', ''$ionicModal'' ]; export default nvModals;

En tu controlador ...

$scope.modals = nvModals;

En la plantilla asociada

ng-click="modals.showMyModal()"

En la plantilla modal

ng-click="hideModal()"


No hay una forma directa de hacerlo en iónica. Sin embargo, si realmente desea que un código común se segregue en un solo lugar, puede usar los servicios para hacerlo. Aquí ''cómo.

  1. En su declaración modal, pase el alcance como nulo, también la declaración modal debería moverse en un servicio.

app.service(''utilsService'', function($ionicModal) { this.showModal = function() { var service = this; $ionicModal.fromTemplateUrl(''templates/login.html'', { scope: null, controller: ''MyModalCotroller'' }).then(function(modal) { service.modal = modal; service.modal.show(); }); }; this.hideModal = function() { this.modal.hide(); }; });

  1. Todos sus métodos comunes también pasarán al mismo servicio.
  1. Agregue la referencia a este servicio en el alcance de su controlador.

app.controller(''indexController'', function($scope, utilsService) { $scope.utilsService = utilsService; });

  1. Ahora, puede llamar a todos los métodos comunes desde la vista directamente utilizando este servicio.

e.g. <button ng-click="utilsService.hideModal()">Hide modal</button>


Ok, he visto muchas soluciones diferentes para manejar mejor los modales iónicos debido a la falta de una opción de controlador o algo similar. Después de jugar con React por un tiempo, se me ocurrió otra opción, más declarativa en mi opinión. Está en ES6 y solo es un prototipo, pero puedes tener una idea:

(function() { ''use strict''; @Inject(''$scope'', ''$ionicModal'', ''$transclude'', ''$rootScope'') class Modal { constructor() { let { animation, focusFirstInput, backdropClickToClose, hardwareBackButtonClose } = this; $transclude((clone, scope) => { let modal = this.createModalAndAppendClone({ scope, animation, focusFirstInput, backdropClickToClose, hardwareBackButtonClose }, clone); this.setupScopeListeners(modal.scope); this.createIsOpenWatcher(); this.addOnDestroyListener(); this.emitOnSetupEvent(modal.scope); }); } setupScopeListeners(scope) { scope.$on(''modal.shown'', this.onShown); scope.$on(''modal.hidden'', this.onHidden); scope.$on(''modal.removed'', this.onRemoved); } addOnDestroyListener() { this.$scope.$on(''$destroy'', () => { this.removeModal(); }); } createIsOpenWatcher() { this.isOpenWatcher = this.$scope.$watch(() => this.isOpen, () => { if (this.isOpen) { this.modal.show(); } else { this.modal.hide(); } }); } emitOnSetupEvent(scope) { this.onSetup({ $scope: scope, $removeModal: this.removeModal.bind(this) }); } createModalAndAppendClone({ scope = this.$rootScope.$new(true), animation = ''slide-in-up'', focusFirstInput = false, backdropClickToClose = true, hardwareBackButtonClose = true }, clone) { let options = { scope, animation, focusFirstInput, backdropClickToClose, hardwareBackButtonClose } this.modal = this.$ionicModal.fromTemplate(''<ion-modal-view></ion-modal-view>'', options); let $modalEl = angular.element(this.modal.modalEl); $modalEl.append(clone); return this.modal; } removeModal() { this.modal.remove(); this.isOpenWatcher(); } } function modal() { return { restrict: ''E'', transclude: true, scope: { ''onShown'': ''&'', ''onHidden'': ''&'', ''onRemoved'': ''&'', ''onSetup'': ''&'', ''isOpen'': ''='', ''animation'': ''@'', ''focusFirstInput'': ''='', ''backdropClickToClose'': ''='', ''hardwareBackButtonClose'': ''='' }, controller: Modal, bindToController: true, controllerAs: ''vm'' } } angular .module(''flight'') .directive(''modal'', modal); })();

Y luego puedes usarlo así:

<modal is-open="vm.isOpen" on-shown="vm.onShown()" on-hidden="vm.onHidden()" on-removed="vm.onRemoved()" on-setup="vm.onSetup($scope, $removeModal)"> <div class="bar bar-header bar-clear"> <div class="button-header"> <button class="button button-positive button-clear button-icon ion-close-round button-header icon" ng-click="vm.closeModal()"></button> </div> </div> <ion-content class="has-header"> <create-flight-form on-submit="vm.submit()"></create-flight-form> </ion-content> </modal>

Abre y cierra el modal con un valor booleano bind para is-open y luego registra callbacks para los diferentes eventos.


Simplemente agregue el controlador que desea usar en el cuerpo del html del modal. Creé un violín para mostrarte un ejemplo basado en el proporcionado en los documentos iónicos: http://jsfiddle.net/g6pdkfL8/

Pero básicamente:

<-- template for the modal window --> <ion-modal-view> <ion-content ng-controller="ModalController"> ... </ion-content> <ion-modal-view>