Angularjs:将所需的指令控制器注入控制器而不是链接功能

时间:2014-01-20 10:18:24

标签: angularjs angularjs-directive

角度正常用例

如果您有父指令和子指令,则在父指令的控制器中创建方法,并在子指令中要求父控制器。 Angular会将父控制器传递给子指令链接函数。

我的用例

我有一个用例,其中child指令是另一个指令的父指令。我在指令中间的指令上面有指令。中间指令是底部最后一个指令所必需的。

在一个简单的世界里,我可以为中间指令创建一个链接方法和一个控制器。 link方法使用顶层控制器处理所有内容,中间控制器传递给bottom指令。

在我的情况下,中间指令的控制器中的方法必须调用父节点中的方法,所以我需要中间控制器中的顶级控制器而不是中间指令的链接函数!

问题

如何将所需的控制器注入控制器而不是链接功能

angular.module('app').directive('top', function () {
    return {
        $scope: true,
        templateUrl: "top.html",
        controller: function() {
            this.topMethod = function() {
                // do something on top
            }
        }
    }
});

angular.module('app').directive('middle', function () {
    return {
        $scope: true,
        templateUrl: "middle.html",
        require: "^top",
        controller: function($scope, $attrs, topController) {
            this.middleMethod = function() {
                // do something in the middle

                // call something in top controller, this is the part that makes everything so complicated
                topController.topMethod();
            }
        }
    }
});

angular.module('app').directive('bottom', function () {
    return {
        $scope: true,
        templateUrl: "bottom.html",
        require: "^middle",
        link: function(scope, element, attrs, middleController) {
            $scope.bottomMethod = function() {
                // do something at the bottom

                // call something in the parent controller
                middleController.middleMethod();
            }
        }
    }
});

3 个答案:

答案 0 :(得分:13)

实际上还有另一种不那么冗长的方式is used by the angular ngModel itself

var parentForm = $element.inheritedData('$formController') || ....

基本上他们使用控制器存储在指令dom元素的data属性中的事实。

仍然有点连线,但不那么冗长,也更容易理解。

我没有看到您无法将所需控制器传递到指令控制器的注入局部区域的原因。

答案 1 :(得分:11)

问题在于编码和链接指令的顺序。假设我们有这样的html结构:

<div top>
   <div middle>
      <div bottom></div>
   </div>
</div>

以及具有大量调试输出的相应(简单)指令:

.directive('top', function() {
    return {
        controller : function($scope, $element, $attrs) {
            this.topMethod = function() {
                console.log('top method');
            }
        },
        compile : function($element, $attrs) {
            console.log('top compile');
            return {
                pre : function($scope, $element, $attrs) {
                    console.log('top pre');
                },
                post : function($scope, $element, $attrs) {
                    console.log('top post');
                }
            };
        }
    }
})

.directive('middle', function() {
    return {
        require : "^top",
        controller : function($scope, $element, $attrs) {
            this.middleMethod = function() {
                console.log('middle method');
                $scope.topController.topMethod();
            }
        },
        compile : function($element, $attrs) {
            console.log('middle compile');
            return {
                pre : function($scope, $element, $attrs, topController) {
                    console.log('middle pre');
                    $scope.topController = topController;
                },
                post : function($scope, $element, $attrs, topController) {
                    console.log('middle post');
                }
            };
        },
    }
})

.directive( 'bottom', function() {
    return {
        require : "^middle",
        compile : function($element, $attrs) {
            console.log('bottom compile');
            return {
                pre : function($scope, $element, $attrs, middleController) {
                    console.log('bottom pre');
                    middleController.middleMethod();
                },
                post : function($scope, $element, $attrs, middleController) {
                    console.log('bottom post');
                }
            };
        }
    }
})

我们得到以下输出:

top compile
middle compile
bottom compile

top pre
middle pre
bottom pre

middle method
top method

bottom post
middle post
top post

我们首先看到编译函数被调用。然后调用预链接函数,之后调用后连接函数。编译和预先从上到下,帖子从下到上。所以我们必须在预连接函数中设置控制器。

答案 2 :(得分:7)

取自romario333的评论: 最干净的解决方案是简单地使用

var topController = $element.controller('top') // pass directive name or controller name

From the docs

  

controller(name) - 检索当前元素或其父元素的控制器。默认情况下,检索与ngController指令关联的控制器。如果name以camelCase指令名提供,则将检索该指令的控制器(例如'ngModel')。

$ element可以注入你的指令控制器。