找不到指令要求的控制器 [英] Controller Required By Directive Can't Be Found

查看:29
本文介绍了找不到指令要求的控制器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个指令,我希望另一个指令能够调用它.我一直在尝试使用指令控制器来尝试实现这一点.

指令一将与指令二位于同一页面,指令一将调用由指令二的控制器公开的方法:

指令 1:

'use strict';angular.module('angularTestApp').directive('fileLibrary', function () {返回 {templateUrl: 'views/manage/file_library/file-library.html',要求:'videoClipDetails',限制:'AE',链接:函数 postLink(scope, element, attrs, videoClipDetailsCtrl) {scope.doSomethingInVideoClipDirective = function() {videoClipDetailsCtrl.doSomething();}}};});

指令二:

'use strict';angular.module('angularTestApp').directive('videoClipDetails', function () {返回 {templateUrl: 'views/video_clip/video-clip-details.html',限制:'AE',控制器:函数($scope,$element){this.doSomething = 函数(){console.log('我做了某事');}},链接:函数 postLink(范围,元素,属性){console.log('videoClipDetails 指令');//将元素作为隐藏开始}};});

使用两者并设置为兄弟的文件:

<div 视频剪辑细节></div><!-- 文件库的主要组件--><div 文件库></div>

我在阅读文档时知道,当指令位于同一元素上时,控制器可以共享,这让我觉得我可能以错误的方式看待这个问题.谁能让我走上正轨?

解决方案

来自 angular.js 指令文档

<块引用>

当指令使用 require 时,除非找到指定的控制器,否则 $compile 将抛出错误.^ 前缀表示该指令在其父级上搜索控制器(如果没有 ^ 前缀,该指令将仅在其自己的元素上寻找控制器).

所以基本上你试图让兄弟姐妹直接交流是不可能的.我遇到了同样的问题,但我不想使用服务进行通信.我想出的是一种使用父指令来管理其兄弟姐妹之间的通信的方法.我发布了github上的示例.

发生的情况是,两个孩子都需要父级(require: '^parentDirective')和他们自己的控制器,这两者都被传递到链接函数中.从那里,每个子控制器都可以获得对父控制器及其所有公共方法的引用,作为各种 API.

下面是其中一个孩子itemEditor

function itemEditor() {var 指令 = {链接:链接,范围: {},控制器:控制器,控制器为:'vm',要求:['^itemManager', 'itemEditor'],templateUrl: 'app/scripts/itemManager/itemManager.directives.itemEditor.html',限制:'A'};返回指令;功能链接(范围,元素,属性,控制器){var itemManagerController = 控制器[0];var itemEditorController = 控制器[1];itemEditorController.itemManager = itemManagerController;itemEditorController.initialize();}功能控制器(){var vm = 这个;//特性vm.itemManager = {};vm.item = { id: -1, name: "", size: "" };//方法vm.initialize = 初始化;vm.updateItem = 更新项;vm.editItem = editItem;//职能函数初始化(){vm.itemManager.respondToEditsWith(vm.editItem);}函数更新项(){vm.itemManager.updateItem(vm.item);vm.item = {};}功能编辑项目(项目){vm.item.id = item.id;vm.item.name = item.name;vm.item.size = item.size;}}}

注意传递到 require 数组中的值如何是父指令的名称和当前指令的名称.然后可以通过 controllers 参数在 link 函数中访问它们.将父指令的控制器分配为当前子指令的属性,然后可以通过该属性在子指令的控制器函数中访问它.

还要注意我如何在子指令的 link 函数中从子控制器调用 initialize 函数.这是建立部分通信线路的地方.

我基本上是说,无论何时您(父指令)收到编辑项目的请求,请使用我的这种名为 editItem 的方法,该方法将 item 作为参数.

这是父指令

function itemManager() {var 指令 = {链接:链接,控制器:控制器,控制器为:'vm',templateUrl: 'app/scripts/itemManager/itemManager.directives.itemManager.html',限制:'A'};返回指令;功能链接(范围,元素,属性,控制器){}功能控制器(){var vm = 这个;vm.updateMethod = null;vm.editMethod = null;vm.updateItem = 更新项;vm.editItem = editItem;vm.respondToUpdatesWith = respondToUpdatesWith;vm.respondToEditsWith = respondToEditsWith;功能更新项目(项目){vm.updateMethod(item);}功能编辑项目(项目){vm.editMethod(item);}函数 responseToUpdatesWith(method) {vm.updateMethod = 方法;}函数 responseToEditsWith(method) {vm.editMethod = 方法;}}}

在父级中,您可以看到 respondToEditsWith 将一个方法作为参数并将该值分配给它的 editMethod 属性.每当调用控制器的 editItem 方法并将 item 对象传递给它时,就会调用此属性,从而调用子指令的 editItem 方法.同样,保存数据的方式与此相反.

更新:顺便说一下,这是我在 coderwall.com 上的一篇博文带有 require 和指令中控制器选项的好例子的原始想法.也就是说,他为该帖子中的最后一个示例推荐的语法对我不起作用,这就是我创建上面引用的示例的原因.

I have a directive that I'd like another directive to be able to call in to. I have been trying to use directive controllers to try to achieve this.

Directive one would be sitting on the same page as directive two, and directive one would call methods exposed by directive two's controller:

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

Directive Two:

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

File where the two are used and set up as siblings:

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

I know reading documentation I picked up that the controllers can be shared when the directives are on the same element, which makes me think I might be looking at this problem the wrong way. Can anyone put me on the right track?

解决方案

From the angular.js documentation on directives

When a directive uses require, $compile will throw an error unless the specified controller is found. The ^ prefix means that this directive searches for the controller on its parents (without the ^ prefix, the directive would look for the controller on just its own element).

So basically what you are trying to do with having siblings directly communicate is not possible. I had run into this same issue but I did not want to use a service for communication. What I came up with was a method of using a parent directive to manage communication between its children, which are siblings. I posted the example on github.

What happens is that both children require the parent (require: '^parentDirective') and their own controller, both of which are passed into the link function. From there each child can get a reference to the parent controller and all of its public methods, as an API of sorts.

Below is one of the children itemEditor

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

Note how the values passed into the require array are the parent directive's name and the current directive's name. These are then both accessible in the link function via the controllers parameter. Assign the parent directive's controller as a property of the current child's and then it can be accessed within the child's controller functions via that property.

Also notice how in the child directive's link function I call an initialize function from the child's controller. This is where part of the communication lines are established.

I'm basically saying, anytime you (parent directive) receive a request to edit an item, use this method of mine named editItem which takes an item as a parameter.

Here is the parent directive

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

Here in the parent you can see that the respondToEditsWith takes a method as a parameter and assigns that value to its editMethod property. This property is called whenever the controller's editItem method is called and the item object is passed on to it, thus calling the child directive's editItem method. Likewise, saving data works the same way in reverse.

Update: By the way, here is a blog post on coderwall.com where I got the original idea with good examples of require and controller options in directives. That said, his recommended syntax for the last example in that post did not work for me, which is why I created the example I reference above.

这篇关于找不到指令要求的控制器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆