web-dev-qa-db-ja.com

angle-ui bootstrap $ modalサービスは代わりにディレクティブを使用します

私が見た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
_
7
core

あなたが抱えている問題は、注入に利用できない値を注入しようとしていることです。インジェクターに登録されている値のみを注入できます。

コードのロジックにも欠陥があります。メインコントローラーでモーダルを作成していますが、ディレクティブでモーダルを閉じようとしています。理想的には、モーダルは(リンク関数を介して)ディレクティブによってトリガーされ、そこからok/cancelすることができます。

私の http://plnkr.co/edit/3p1rXAymd7BilyklgxKy?p=preview を参照してください。考えられるアプローチの1つとして、メインコントローラーのモーダルを閉じてキャンセルするコードを保持しています。

    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());
    });
  };
});
5
thedoctor

問題は、$modalInstance$modal.openに提供したコントローラーにのみ注入できることです。ソースをチェックしてください ここ

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

基本的に、コントローラーへの依存関係として$modalInstanceを追加しようとすると、AngularJSは$modalInstanceProviderという名前の登録済みグローバルプロバイダーを探します。ここで問題となるのは、上記のコードを理解している場合、$modalInstancenotグローバルに登録されたプロバイダーではないということです。 $modal.openに渡すコントローラーの依存関係としてのみ「存在」します。

残りのコードを読むと、$modal.openmodalInstanceを返すことに気付くでしょう。おそらく、それを使用できます。

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

モーダルを簡単に作成するためのディレクティブを作成します。モーダルコンテンツは、テンプレートビューに基づいています。

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

モーダルコントローラー(HelloCtrl)はビューコントローラー(Hello2)の後にレンダリングされるため、モーダル出力が「HelloWorldsszzXico」になることに注意してください。

参照

3
Fernando Felix

返信はさらに遅くなりますが、誰かが役に立つと思うかもしれません。

私はFernandoFelixの回答を強化し、コントローラーと通信する独自​​の非常に柔軟なディレクティブを作成しました。これは、この質問の解決策になると思います。

指令

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>

ポップアップタイプごとに1つのコントローラーとテンプレートであるため、次の方法で複数回呼び出すことができます。

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

モーダルサイズなど

モーダルリンク/ボタンのパラメータsize = "sm | lg"を追加するだけです。ここをクリックしてモーダルを開きます。標準サイズの場合は、パラメーターをスキップします。リンク関数attrsを使用して、自分で拡張することができます。

2
Karol Websky

私は神田ですレイトリプレイ最も簡単な方法は使用することです

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

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

これは、ディレクティブコントローラーから機能します。