Подтвердить что ты не робот

Передайте контроллер в $ionicModal

Мне интересно, можете ли вы передать контроллер в службу $ionicModal. Что-то вроде.

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

Небольшой контекст: я хотел бы иметь модальный, который распространяется через приложение, и я не хочу повторять все методы (скрыть, показать, кнопки внутри модального) в каждом контроллере, и я хотел бы удалить методы от "Main Controller", чтобы сохранить чистоту. Это будет инкапсулировать функциональность модального.

Есть ли способ сделать это? Благодаря

4b9b3361

Ответ 1

Просто добавьте контроллер, который вы хотите использовать в теле html модального. Я создал скрипку, чтобы показать вам пример, основанный на примере, представленном в ионных документах: http://jsfiddle.net/g6pdkfL8/

Но в основном:

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

Ответ 2

Нет прямого способа сделать это в ионной форме. Однако, если вы действительно хотите, чтобы какой-то общий код был разделен в одном месте, Вы можете использовать службы для этого. Вот как.

  • В своем модальном объявлении пропустите область действия как null, также модальное объявление должно перемещаться в службе.
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. Все ваши общие методы также перейдут в одну и ту же службу.

  1. Добавьте ссылку на эту службу в область вашего контроллера.
    app.controller('indexController', function($scope, utilsService) {
        $scope.utilsService = utilsService;
    });

  1. Теперь вы можете вызвать все общие методы из представления напрямую с помощью этой службы.
e.g. <button ng-click="utilsService.hideModal()">Hide modal</button>

Ответ 3

Основываясь на этом вопросе и других потребностях, я создаю полезную услугу.

В любом случае используйте код CodePen, обновленный, улучшенный и предоставляющий параметр "options" в $ionicModal.

Смотрите это сообщение: Ионный модальный сервис или смотрите в действии: 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....
}

}]);

Ответ 4

Создайте директиву, которая будет использоваться внутри модальной и внутри директивы, которую вы можете назначить модальным своим собственным контроллером и областью. Если кому-то нужен какой-то примерный код, я могу что-то придумать.

Ответ 5

Я искал простой способ подключить контроллер к модальному экземпляру и управлять всеми модалами с помощью одной службы. Кроме того, я хотел, чтобы модальная была собственная изолированная область. Я был недоволен использованием ng-controller, и я нашел другие ответы слишком сложными до такой степени, что вы могли бы легко потерять отслеживание области и в конечном итоге получить круговые или неидентифицируемые зависимости. Для моих целей я создал следующую службу.

Вы можете передать необязательный параметр parentScope, чтобы явно назначить родительскую область для созданной области модальности.

Вы можете легко изменить метод instantiateModal, чтобы принять параметры $ionicModal в качестве аргумента - мне просто не нужно было это делать.

BTW. Я использую загрузчик Babel-загрузчика Webpack для транспиляции, а html-loader - для загрузки шаблонов. Но в простейшей форме это просто базовая услуга.

/**
 * 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()"

В модальном шаблоне

ng-click="hideModal()"

Ответ 6

Хорошо, я видел много разных решений для лучшей обработки ионных модалов из-за отсутствия опции контроллера или чего-то подобного. После игры с 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 и затем регистрируете обратные вызовы для разных событий.