我是否可以在指令中使用ng-controller设置控制器?

时间:2015-05-21 13:49:20

标签: angularjs angularjs-directive angularjs-controller

我有(以下)html:

    <div ng-controller="MyController">
       <my-sub-directive></my-sub-directive>
    </div>

控制器的外观并不重要:

app.controller("MyController", function($scope) {
   $scope.foo = "bar";
})

我的指令如下:

function mySubDirective() {
        return {
            restrict: "E",
            templateUrl:"aTemplate.html",
            require: "^MyController",
            link: function($scope, element) {

            }
        };
    }
app.directive("mySubDirective", mySubDirective);

在文档中,他们总是在require - 属性中指定另一个指令,但它表示这意味着您需要控制器。所以我想尝试这个解决方案。但是我收到了错误

&#34;控制器&#39; MyController&#39;,指令&#39; mySubDirective&#39;所要求的,无法找到&#34;。

如果由ng-controller设置控制器,是否不能要求指令中的控制器?

2 个答案:

答案 0 :(得分:5)

你只能这样做:

require: "^ngController"

所以,你不能比那更具体,即你不能按名称要求"MainCtrl""MyController",但它会让你获得控制器实例: / p>

.controller("SomeController", function(){
   this.doSomething = function(){
     //
   };
})

.directive("foo", function(){
  return {
    require: "?^ngController",
    link: function(scope, element, attrs, ctrl){
      if (ctrl && ctrl.doSomething){
        ctrl.doSomething();
      }
    }
  }
});
<div ng-controller="SomeController">
   <foo></foo>
</div>
但是,我不认为这是一个很好的方法,因为它使指令非常依赖使用。您可以按照注释中的建议直接传递控制器实例 - 它使它更明确:

<div ng-controller="SomeController as ctrl">
  <foo ctrl="ctrl"></foo>
</div>

但它仍然是一个过于通用的对象,很容易被你的指令用户误用。

相反,公开一个定义良好的API(通过属性)并将引用传递给控制器​​中定义的函数/属性:

<div ng-controller="SomeController as ctrl">
  <foo do="ctrl.doSomething()"></foo>
</div>

答案 1 :(得分:0)

您可以在指令链接功能中使用element.controller()来测试ngController指定的最近控制器。这种方法的局限在于它不会告诉你它是哪个控制器。可能有几种方法可以做到,但我选择命名控制器构造函数,并在范围内公开它,因此您可以使用instanceof

// Deliberately not adding to global scope
(function() {

  var app = angular.module('my-app', []);

  // Exposed in so can do "instanceof" in directive
  function MyController($scope) {}
  app.controller('MyController', MyController);

  app.directive("foo", function(){
    return {
      link: function($scope, $element){
        var controller = $element.controller();

        // True or false depending on whether the closest 
        // ngController is a MyController
        console.log(controller instanceof MyController);
      }
    };
  })

})();

您可以在http://plnkr.co/edit/AVmr7Eb7dQD70Mpmhpjm?p=preview

看到这一点

但是,如果您嵌套了ngController s,并且您想要测试一个不一定是最接近的那个,那么这项工作就不会起作用。为此,您可以定义一个递归函数来遍历DOM树:

  app.directive("foo", function(){

    function getAncestorController(element, controllerConstructor) {
      var controller = element.controller();
      if (controller instanceof controllerConstructor) {
        return controller;
      } else if (element.parent().length) {
        return getAncestorController(element.parent(), controllerConstructor);
      } else {
        return void(0); // undefined
      }
    }

    return {
      link: function(scope, element){
        var controller = getAncestorController(element, MyController);

        // The ancestor controller instance, or undefined
        console.log(controller);
      }
    };
  })

您可以在http://plnkr.co/edit/xM5or4skle62Y9UPKfwG?p=preview

看到这一点

供参考docs表示controller函数可用于查找ngController指定的控制器:

  

默认情况下,检索与ngController指令关联的控制器