将控制器传递给$ ionicModal

时间:2014-12-11 23:20:34

标签: ionic-framework

我想知道你是否可以将控制器传递给$ ionicModal服务。像。的东西。

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

一点上下文:我想有一个分布在应用程序中的模态,我不想在每个控制器中重复所有方法(隐藏,显示,模态内的按钮),我想删除方法来自'主控制器'保持清洁。这将封装模态的功能。

有没有办法做到这一点。 感谢

6 个答案:

答案 0 :(得分:31)

只需在模式的html主体中添加要使用的控制器即可。我创建了一个小提琴,向您展示离心文档中提供的示例:http://jsfiddle.net/g6pdkfL8/

但基本上是:

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

答案 1 :(得分:25)

在离子方面没有这样做的直接方法。但是,如果你真的希望在一个地方隔离一些共同的代码, 您可以使用服务来执行此操作。这里&#39;如何。

  
      
  1. 在你的模态声明中,将范围传递为null,模态声明也应该在服务中移动。
  2.   
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. 您的所有常用方法也将转移到同一服务中。
  2.   

  
      
  1. 将对此服务的引用添加到控制器的范围中。
  2.   
    app.controller('indexController', function($scope, utilsService) {
        $scope.utilsService = utilsService;
    });

  
      
  1. 现在,您可以直接使用此服务从视图中调用所有常用方法。
  2.   
e.g. <button ng-click="utilsService.hideModal()">Hide modal</button>

答案 2 :(得分:21)

基于这个问题和其他需求,我创建了一个有用的服务。

无论如何使用CodePen代码,这个更新,改进,它使参数&#39;选项&#39; $ ionicModal。

请参阅此帖子:Ionic modal service或查看操作: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
})();

用法:

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

您可以使用其他服务来集中所有模态的配置:

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

}]);

答案 3 :(得分:5)

创建一个在模态内部使用的指令,在指令内部可以为模态分配它自己的控制器和范围。如果有人想要一些示例代码,我可以提出一些建议。

答案 4 :(得分:0)

我一直在寻找一种简单的方法将控制器连接到模态实例并使用单个服务管理所有模态。此外,我希望模态具有它自己的孤立子范围。我对使用UIViewController感到不满意,并且我发现其他答案过于复杂,以至于您很容易忽略范围并最终导致循环或无法识别的依赖关系。我为自己的目的创建了以下服务。

您可以传递一个可选的ng-controller参数,以明确地将父范围分配给创建的模态范围。

您可以轻松修改parentScope方法以接受$ ionicModal选项作为参数 - 我只是不需要它。

BTW - 我正在使用Webpack babel-loader进行转换,而html-loader则用于加载模板。但是,它是最简单的形式,它只是一项基本服务。

instantiateModal
  

在你的控制器......

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

在相关模板

$scope.modals = nvModals;
  

在模态模板中

ng-click="modals.showMyModal()"

答案 5 :(得分:0)

好的,我已经看到很多不同的解决方案可以更好地处理离子模态,因为缺少控制器选项或类似的东西。 在玩了React一段时间后,我提出了另一种选择,在我看来更具说明性。在ES6中,只是一个原型,但你可以有一个想法:

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

})();

然后你可以像这样使用它:

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

使用布尔值绑定到is-open打开和关闭模态,然后为不同的事件注册回调。