web-dev-qa-db-ja.com

指令で必要なコントローラーが見つかりません

別のディレクティブを呼び出したいディレクティブがあります。私はこれを達成するためにディレクティブコントローラーを使用しようとしています。

ディレクティブ1はディレクティブ2と同じページにあり、ディレクティブ1はディレクティブ2のコントローラーによって公開されたメソッドを呼び出します。

ディレクティブ1:

'use strict';
angular.module('angularTestApp')
    .directive('fileLibrary', function () {
        return {
            templateUrl: 'views/manage/file_library/file-library.html',
            require: 'videoClipDetails',
            restrict: 'AE',
            link: function postLink(scope, element, attrs, videClipDetailsCtrl) {
                scope.doSomethingInVideoClipDirective = function() {
                    videClipDetailsCtrl.doSomething();
                }
            }
        };
    });

ディレクティブ2:

'use strict';
angular.module('angularTestApp')
    .directive('videoClipDetails', function () {
        return {
            templateUrl: 'views/video_clip/video-clip-details.html',
            restrict: 'AE',
            controller: function($scope, $element) {
                this.doSomething = function() {
                    console.log('I did something');
                }
            },
            link: function postLink(scope, element, attrs) {
                console.log('videoClipDetails directive');
                //start the element out as hidden
            }
        };
    });

2つが使用され、兄弟として設定されているファイル:

<div>
    <div video-clip-details></div>
    <!-- main component for the file library -->
    <div file-library></div>
</div>

ディレクティブが同じ要素にあるときにコントローラーを共有できることを取り上げたドキュメントを読んでいるので、この問題を間違った方法で見ているのではないかと思います。誰でも私を正しい方向に導くことができますか?

23
binarygiant

Angular.jsから ディレクティブに関するドキュメント

ディレクティブがrequireを使用する場合、$compileは、指定されたコントローラーが見つからない限りエラーをスローします。 ^プレフィックスは、このディレクティブがその親でコントローラーを検索することを意味します(^プレフィックス、ディレクティブは独自の要素でのみコントローラーを探します)。

したがって、基本的に兄弟が直接通信することで何をしようとしているかは不可能です。これと同じ問題に遭遇しましたが、通信にサービスを使用したくありませんでした。私が思いついたのは、兄弟である子の間の通信を管理するために親ディレクティブを使用する方法でした。 githubの例 を投稿しました。

起こるのは、両方の子が親(require: '^parentDirective')および独自のコントローラー。両方ともリンク関数に渡されます。そこから、各子は、親コントローラーとそのすべてのパブリックメソッドへの参照を、一種のAPIとして取得できます。

以下は、子itemEditorの1つです

function itemEditor() {
    var directive = {
        link: link,
        scope: {},
        controller: controller,
        controllerAs: 'vm',
        require: ['^itemManager', 'itemEditor'],
        templateUrl: 'app/scripts/itemManager/itemManager.directives.itemEditor.html',
        restrict: 'A'
    };

    return directive;

    function link(scope, element, attrs, controllers) {
        var itemManagerController = controllers[0];
        var itemEditorController = controllers[1];

        itemEditorController.itemManager = itemManagerController;

        itemEditorController.initialize();
    }

    function controller() {
        var vm = this;

        // Properties
        vm.itemManager = {};
        vm.item = { id: -1, name: "", size: "" };

        // Methods
        vm.initialize = initialize;
        vm.updateItem = updateItem;
        vm.editItem = editItem;

        // Functions
        function initialize() {
            vm.itemManager.respondToEditsWith(vm.editItem);
        }

        function updateItem() {
            vm.itemManager.updateItem(vm.item);
            vm.item = {};
        }

        function editItem(item) {
            vm.item.id = item.id;
            vm.item.name = item.name;
            vm.item.size = item.size;
        }
    }
}

require配列に渡される値が、親ディレクティブの名前と現在のディレクティブの名前であることに注意してください。その後、これらはlink関数でcontrollersパラメーターを介してアクセスできます。親ディレクティブのコントローラーを現在の子のコントローラーとして割り当てると、そのプロパティを介して子のコントローラー関数内でアクセスできます。

また、子ディレクティブのlink関数で、子のコントローラーからinitialize関数を呼び出す方法にも注目してください。これは、通信回線の一部が確立される場所です。

私は基本的に、あなた(親ディレクティブ)がアイテムを編集するリクエストを受け取ったときはいつでも、editItemという名前の私のメソッドをitemをパラメーターとして使用します。

これが親ディレクティブです

function itemManager() {
    var directive = {
        link: link,
        controller: controller,
        controllerAs: 'vm',
        templateUrl: 'app/scripts/itemManager/itemManager.directives.itemManager.html',
        restrict: 'A'
    };

    return directive;

    function link(scope, element, attrs, controller) {

    }

    function controller() {
        var vm = this;

        vm.updateMethod = null;
        vm.editMethod = null;

        vm.updateItem = updateItem;
        vm.editItem = editItem;
        vm.respondToUpdatesWith = respondToUpdatesWith;
        vm.respondToEditsWith = respondToEditsWith;

        function updateItem(item) {
            vm.updateMethod(item);
        }

        function editItem(item) {
            vm.editMethod(item);
        }

        function respondToUpdatesWith(method) {
            vm.updateMethod = method;
        }

        function respondToEditsWith(method) {
            vm.editMethod = method;
        }
    }
}

ここで、親では、respondToEditsWithがメソッドをパラメーターとして取り、その値をeditMethodプロパティーに割り当てることがわかります。このプロパティは、コントローラのeditItemメソッドが呼び出され、itemオブジェクトが渡されるたびに呼び出され、子ディレクティブのeditItemメソッドを呼び出します。同様に、データの保存も同じように逆に機能します。

Update:ところで、ここに coderwall.comのブログ投稿 ここで、 requireおよびディレクティブのコントローラーオプション。とは言っても、その投稿の最後の例で彼が推奨した構文は私にとってはうまくいきませんでした。そのため、上記で参照した例を作成しました。

16
seangwright

ここでやろうとしている方法で兄弟要素間で通信する必要がある実際の方法はありません。 requireは、2つのディレクティブが同じ要素である場合に設定した方法で機能します。

ただし、両方のディレクティブには使用したいtemplateUrlが関連付けられており、要素ごとに1つしか使用できないため、これを行うことはできません。

ただし、これを機能させるために、HTMLをわずかに異なる構造にすることができます。基本的に、1つのディレクティブを他のディレクティブ(トランスクルード)内に配置し、require: '^videoClipDetails'。それはそれを見つけるために親に見えることを意味します。これを実証するためにフィドルを設定しました: http://jsfiddle.net/WwCvQ/1/

これは親の事を機能させるコードです:

// In videoClipDetails
template: '<div>clip details<div ng-transclude></div></div>',
transclude: 'true',
...
// in markup
<div video-clip-details> 
    <div file-library></div>
</div>
// in fileLibrary
require: '^videoClipDetails',

ご質問がある場合はお知らせください!

7
hassassin