angular-ui bootstrap $modal 服务使用指令代替

angular-ui bootstrap $modal service using directive instead

我看到的使用 angular-ui/bootstrap 的 $modal 的示例总是看起来像这样:

    $modal.open({
        templateUrl: 'modaltemplate.html',
        controller: function($scope) {
            ...
        }
    });

如果我想改用指令怎么办?像这样:

    $modal.open({
        template: '<my-modal-directive></my-modal-directive>'
        // no "controller" property; use directive's controller
    });

my-modal-directive 的标记呈现良好,我已将 controller 属性 移动到 my-modal-directive 定义对象中,但现在从 my-modal-directive:

Error: [$injector:unpr] Unknown provider: $modalInstanceProvider <- $modalInstance

谁能给我指出一个示例,其中 $modal 使用一个指令,该指令定义了 controller

例如,这有效,我用指令替换了 templateUrl

http://plnkr.co/edit/YrGaF83GH6bzZPRR55GK?p=preview

但是当我将控制器从 $modal.open() 移动到指令中时,错误发生了:

http://plnkr.co/edit/aLBT239EpL004DRh4jll?p=preview

问题是 $modalInstance 只能注入到您提供给 $modal.open 的控制器中。 查看来源 here:

$modal.open = function (modalOptions) {
    ...
    var modalInstance = {
        ...
    };
    ...
    if (modalOptions.controller) {
        ...
        ctrlLocals.$modalInstance = modalInstance;
        ...
        ctrlInstance = $controller(modalOptions.controller, ctrlLocals);
        ...
    }
    ...
}

本质上,当您尝试将 $modalInstance 添加为控制器的依赖项时,AngularJS 会查找名为 $modalInstanceProvider 的已注册全局提供程序。现在的问题是,如果您理解上面的代码,那么 $modalInstance 而不是 全球注册的提供商。它仅 "exists" 作为传递给 $modal.open.

的控制器的依赖项

如果您阅读其余代码,您会注意到 $modal.open returns modalInstance,也许您可​​以使用它。

类似于this:

function SomeController($modal) {
    $scope.modal = {
        instance: null
    };

    $scope.modal.instance = $modal.open({
        template: '<my-modal-directive modal="modal"></my-modal-directive>',
        scope: $scope
    });
}

function MyModalDirective() {
    scope: {
        modal: '='
    },
    link: function($scope) {
         // here you can access $scope.modal.instance
    }
} 

您遇到的问题是您正在尝试注入不可用于注入的值。只能注入注入器注册的值。

你的代码逻辑也有缺陷,你在主控制器中创建模态,但试图在指令中关闭它。理想情况下,模式应该由指令触发(通过它的 link 函数),然后你可以从那里 ok/cancel 它。

查看我的 http://plnkr.co/edit/3p1rXAymd7BilyklgxKy?p=preview 了解一种可能的方法,我在主控制器中保留了关闭和取消模态的代码。

    angular.module('ui.bootstrap.demo', ['ui.bootstrap']);
angular.module('ui.bootstrap.demo').directive('myModal', function() {
    return {
        restrict: 'E',
        templateUrl: 'myModalContent.html',
        controller: function ($scope) {
          $scope.selected = {
            item: $scope.items[0] 
          };
        }
    };
});
angular.module('ui.bootstrap.demo').controller('ModalDemoCtrl', function ($scope, $modal, $log) {

  $scope.items = ['item1', 'item2', 'item3'];

  $scope.open = function (size) {
    var modalInstance;
    var modalScope = $scope.$new();
    modalScope.ok = function () {
            modalInstance.close(modalScope.selected);
    };
    modalScope.cancel = function () {
            modalInstance.dismiss('cancel');
    };      

    modalInstance = $modal.open({
      template: '<my-modal></my-modal>',
      size: size,
      scope: modalScope
      }
    );

    modalInstance.result.then(function (selectedItem) {
      $scope.selected = selectedItem;
    }, function () {
      $log.info('Modal dismissed at: ' + new Date());
    });
  };
});

我创建了一个指令来轻松创建模态。模态内容基于模板视图。

angular.module('your_app').directive('modalViewUrl', function ($modal) {

    return {
        restrict: 'A', // A: attribute
        scope: { // isolate scope
            'modalViewUrl': '@', // modal view url to render the modal content
            'modalController': '@' // modal view controller (optional)
        },
        link: function($scope, element, attrs){

            element.bind('click', function(){

                var template = 
                    '<div class="modal-body">' + 
                    '<button ng-click="$close()" type="button" class="close" aria-label="Close">' +
                    '<span aria-hidden="true">&times;</span>' +
                    '</button>' +
                    '<div ng-include="\'' + $scope.modalViewUrl + '\'"></div>' +
                    '</div>';

                // see modal reference from ui bootstrap at <http://angular-ui.github.io>
                var modalInstance = $modal.open({
                    animation: true,
                    template: template,
                    controller: $scope.modalController,                    
                });
            });
        }
    };
});

使用示例:

index.html

<a modal-view-url="hello.html" modal-controller="HelloCtrl" href="#">
    Click here to open the modal
</a>

hello.html

<h1> Hello World {{name}} </h1>

HelloCtrl.js

angular.module('yourApp').controller('HelloCtrl', 
                function ($scope, $modalInstance) {
    // $modalInstance: same from  from ui bootstrap
    $scope.name = "Xico";
});

模态视图可以有自己的控制器。示例:

hello.html(修改)

<h1 ng-controller="Hello2Ctrl"> {{msg}} {{name}} </h1>

Hello2Ctrl.js

angular.module('yourApp').controller('Hello2Ctrl', 
                function ($scope) {
    $scope.msg = "Hello Worldsszz";
    $scope.name = "Zefa";
});

观察模态输出将是 "Hello Worldsszz Xico",因为模态控制器 (HelloCtrl) 将在视图控制器 (Hello2) 之后呈现。

Reference

我回复有点晚,最简单的方法是使用

$scope.$parent.$close(result);

$scope.$parent.$dismiss(reason);

这适用于您的指令控制器。

更晚的回复,但有人可能会觉得它有用。

我增强了 Fernando Felix 的回答,并制作了我自己的与控制器通信的非常灵活的指令,我认为这可能是这个问题的解决方案。

指令

var modalUrl = function ($modal) {
    return {
        restrict: 'A', // A: attribute
        scope: { // isolate scope
            'modalUrl': '@', // modal view url to render the modal content
            'modalController': '@', // modal view controller (optional)
            'value': "="
        },
        link: function(scope, element, attrs){
            console.log('modalUrl link');

            var modalInstance;
            var template = [
                    '<div class="modal-body">',
                        '<button ng-click="$close()" type="button" class="close" aria-label="Close">',
                            '<span aria-hidden="true">&times;</span>',
                        '</button>',
                        '<div ng-include="\'' + scope.modalUrl + '\'"></div>',
                    '</div>'
                ].join('');


            element.bind('click', function(){
                // see modal reference from ui bootstrap at <http://angular-ui.github.io>
                modalInstance = $modal.open({
                    size: attrs.size,
                    animation: true,
                    template: template,
                    resolve: {
                        params: function () {
                            console.log('value passed to modal:');
                            console.log(scope.value);
                            return scope.value;
                        }
                    },
                    controller: scope.modalController
                });

                modalInstance.result.then(
                    function (returnValue) {
                        // alert('value: '+returnValue);
                        console.log('modal returnValue:');
                        console.log(returnValue);
                        scope.value = returnValue;
                    }, function () {
                        console.log('Modal dismissed at: ' + new Date());
                    }
                );

            });

        }
    };
}
modalUrl.$inject = ['$modal'];
angular.module('app').directive('modalUrl', modalUrl);

控制器

var HelloCtrl = function ($scope, $modalInstance, modalVal) {
    // $modalInstance: same from  from ui bootstrap
    console.log('Hello init!');
    // modalVal is the init modal value passed via directive
    console.log(modalVal);

    // your code
    $scope.name = modalVal;

    $scope.ok = function() {                                        
        $modalInstance.close(this.name); // returnValue
    };

    $scope.cancel = function() {
        $modalInstance.dismiss('cancel');
    };
}
HelloCtrl.$inject = ['$scope', '$modalInstance','params'];
angular.module('app').controller('HelloCtrl',HelloCtrl);

内联模板

<script type="text/ng-template" id="hello.html">
    <div class="modal-header">
        <h3 class="modal-title">I'm a modal!</h3>
    </div>
    <div class="modal-body">
        <input type="text" ng-model="name" />                                        
    </div>
    <div class="modal-footer">
        <button class="btn btn-primary" ng-click="ok()">OK</button>
        <button class="btn" ng-click="cancel()">Cancel</button>
    </div>
</script>

每个弹出窗口类型一个控制器和一个模板,然后您可以多次调用它:

<a modal-url="hello.html" modal-controller="HelloCtrl" value="yourVal" ng-init="yourVal='test'" href="#">Click here to open the modal</a>

您可以使用任何方式初始化值 - 即。对象、数组等

或外部模板

几乎相同,只是 url 变化和模板文件用于模板。

<a modal-url="/modal/test1.html" modal-controller="HelloCtrl" value="yourVal" ng-init="yourVal='test'" href="#">Click here to open the modal</a>

test1.html

<div class="modal-header">
    <h3 class="modal-title">I'm a modal!</h3>
</div>
<div class="modal-body">
    <input type="text" ng-model="name" />                                        
</div>
<div class="modal-footer">
    <button class="btn btn-primary" ng-click="ok()">OK</button>
    <button class="btn" ng-click="cancel()">Cancel</button>
</div>

模态大小等

只需为模态 link/button 添加参数 size="sm|lg" 即。 单击此处打开模态 对于标准尺寸,请跳过该参数。 您可以使用 link 函数 attrs.

自行增强它