Angularjs 如何访问父指令';通过递归地要求它来调用控制器?

Angularjs 如何访问父指令';通过递归地要求它来调用控制器?,angularjs,angularjs-directive,angularjs-controller,Angularjs,Angularjs Directive,Angularjs Controller,我试图递归地访问父“box”指令的控制器: <body ng-app="main"> <!-- no nesting: parent is the just body --> <box></box> <script type="text/javascript"> angular.module('main', []) .directive('box', function() { return { restric

我试图递归地访问父“box”指令的控制器:

<body ng-app="main">

<!-- no nesting: parent is the just body -->
<box></box>

<script type="text/javascript">
angular.module('main', [])
.directive('box', function() {
    return {
        restrict: 'E',
        controller: function() { },
        require: '?^box',  // find optional PARENT "box" directive
        link: function(scope, iElement, iAttrs, controller) {
            // controller should be undefined, as there is no parent box
            alert('Controller found: ' + (controller !== undefined));
        }
    };
});
</script>
</body>

require
将控制器从required(parent)指令注入当前指令(从angular文档:“require-require另一个指令,并将其控制器作为第四个参数注入链接函数”)

也许你已经得到你想要的了?也就是说,父控制器通过
控制器
参数注入子控制器。

好的,找到它了

如果要获取父元素的控制器,请执行以下操作:

...
link: function(scope, iElement, iAttrs, controller) {
    // http://docs.angularjs.org/api/angular.element
    // jQuery/jqLite Extras:
    //
    // controller(name) - retrieves the controller of the current element or its parent.
    // By default retrieves controller associated with the ngController directive.
    // If name is provided as camelCase directive name, then the controller for this
    // directive will be retrieved (e.g. 'ngModel').
    var parentCtrl = iElement.parent().controller('box');
}
...
这将返回父指令的控制器或更高级别的父指令的控制器,如果您需要确保获得直接父指令的控制器,我发现了这一点(可能有更好的解决方案,我不知道):

例1:

<box id="a">
    <box id="b"></box>
<box>
在“框a”上调用链接函数时,在这两种情况下,parentCtrl都是未定义的。
在“框b”上调用链接函数时,parentCtrl在这两种情况下仍然是“框a”的控制器,但hasDirectBoxParent是
false
,因此您可以区分父元素和祖辈元素。

自Angular 1.3以来,您可以使用两个重音符号
^
“仅”在父元素中搜索指令

引自:

  • (无前缀)
    -在当前元素上找到所需的控制器。如果找不到,则抛出错误
  • -尝试找到所需的控制器,如果找不到,则将null传递给链接fn
  • ^
    -找到 通过搜索元素及其父元素,找到所需的控制器。如果找不到,则抛出错误
  • ^
    -通过搜索元素的父元素来定位所需的控制器。如果找不到,则抛出错误
  • ?^
    -尝试通过搜索元素及其父元素来定位所需的控制器,如果未找到,则将null传递给链接fn
  • ?^^
    -尝试通过搜索元素的父元素来定位所需的控制器,如果未找到,则将null传递给链接fn

在您的例子中,将
require:'?^box',
替换为
require:'?^box',

,如您所见,我的原始示例中没有父框,因此我希望将
undefined
作为链接函数的第四个参数,而不是实例的控制器本身,而是您正在声明的控制器。因此,父控制器获得该控制器,子控制器(如果存在)从中继承。您的目标是了解特定指令是父指令还是子指令?如果是这样的话,也许您想看看$parent作用域?事实上,我不想在这种特殊情况下使用作用域,因为作用域可能会变得棘手,特别是如果您需要使用独立的作用域。此外,最佳实践是使用控制器和
require
进行指令间通信。我的观点是,当你需要一个具有不同名称的父指令时,它就像一个符咒,为什么你不能递归地这样做呢。但是我认为使用不同的名称作为顶级指令会更容易。一个想法是,您可以在控制器中声明一个变量,如
first
,并将其设置为1。第一次看到您是第一个调用方,因此是家长,然后将first设置为0,以便其他所有人都知道自己是孩子。这是一个有点黑客,所以你可能仍然更高兴与2个不同的指令。但我想我会把它扔掉以防万一。
...
controller: function($scope, $element) {
    // store the element in controller, we'll need it later
    this.$element = $element;
},
// works in both pre and post link functions
link: function() {
    var parentElement = $element.parent();
    var parentCtrl = parentElement.controller('box');

    var hasDirectBoxParent = parentCtrl && parentCtrl.$element[0] === parentElement[0];

}
...
<box id="a">
    <box id="b"></box>
<box>
<box id="a">
    <div>
        <box id="b"></box>
    </div>
<box>