Pass a controller to $ionicModal

后端 未结 6 1304
醉酒成梦
醉酒成梦 2020-12-24 01:34

I am wondering if you can pass a controller to the $ionicModal service. Something like.

$ionicModal.fromTemplateUrl(\'templates/login.html\', {
  scope: $sco         


        
相关标签:
6条回答
  • 2020-12-24 01:49

    Based on this question and other needs I create a service that can be useful.

    Anyway use the CodePen code, this updated, improved and it makes available the parameter 'options' of $ionicModal.

    See this post: Ionic modal service or see in operation: 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
    })();
    

    Usage:

    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
     });
    

    You can use another service to centralize the configuration of all modals:

    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....
    }
    
    }]);
    
    0 讨论(0)
  • 2020-12-24 01:55

    Just add the controller you want to use in the body of the html of the modal. I created a fiddle to show you an example based off the one provided in the ionic docs: http://jsfiddle.net/g6pdkfL8/

    But basically:

    <-- template for the modal window -->
    <ion-modal-view>
    <ion-content ng-controller="ModalController">
     ...
    </ion-content>
    <ion-modal-view>
    
    0 讨论(0)
  • 2020-12-24 01:59

    I was looking for a simple way to attach a controller to a modal instance and manage all modals with a single service. Also, I wanted the modal to have it's own isolated child scope. I wasn't satisfied with using ng-controller and I found other answers to be overly complicated to the point where you could easily loose track of scope and end up with circular or unidentifiable dependencies. I created the following service for my purposes.

    You can pass an optional parentScope parameter to explicitly assign a parent scope to the created modal scope.

    You could easily modify the instantiateModal method to accept $ionicModal options as an argument - I just didn't have the need for it.

    BTW - I'm using the Webpack babel-loader for transpilation and the html-loader to load the templates. But, in it's simplest form, it's just a basic service.

    /**
     * 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;
    

    In your controller...

    $scope.modals = nvModals;
    

    In the associated template

    ng-click="modals.showMyModal()"
    

    In the modal template

    ng-click="hideModal()"
    
    0 讨论(0)
  • 2020-12-24 02:08

    There's no direct way of doing so in ionic. However, if you really want to have some common code being segregated at one place, You can use services to do so. Here' how.

    1. In your modal declaration, pass scope as null, also the modal declaration should move in a service.
    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. All your common methods will also move down into the same service.

    1. Add the reference to this service into your controller's scope.
        app.controller('indexController', function($scope, utilsService) {
            $scope.utilsService = utilsService;
        });
    

    1. Now, you can call all the common methods from the view directly using this service.
    e.g. <button ng-click="utilsService.hideModal()">Hide modal</button>
    
    0 讨论(0)
  • 2020-12-24 02:09

    Ok, I have seen a lot of different solutions to better handling Ionic modals because of the lack of a controller option or something similar. After playing with React for a while I came up with another option, more declarative in my opinion. Is in ES6 and just a prototype but you can have an 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);
    
    })();
    

    And then you can use it like this:

    <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>
    

    You open and close the modal with a boolean value bind to is-open and then register callbacks for the different events.

    0 讨论(0)
  • 2020-12-24 02:14

    Create a directive to be used inside the modal and inside the directive you can assign the modal it's own controller and scope. If someone wants some example code I can put something up.

    0 讨论(0)
提交回复
热议问题