如何从另一个控制器访问所需的控制器?

How to access a require'd controller from another controller?

我有一个看起来像这样的 Angular 1.3 模块(使用 controllerAs 需要存在父指令的指令):

angular.module('fooModule', [])

.controller('FooController', function ($scope) {
  this.doSomething = function () {
    // Accessing parentDirectiveCtrl via $scope
    $scope.parentDirectiveCtrl();
  };
})

.directive('fooDirective', function () {
  return {
    // Passing in parentDirectiveCtrl into $scope here
    link: function link(scope, element, attrs, parentDirectiveCtrl) {
      scope.parentDirectiveCtrl = parentDirectiveCtrl;
    },
    controller: 'FooController',
    controllerAs: 'controller',
    bindToController: true,
    require: '^parentDirective'
  };
});

这里我只是用$scope穿过parentDirectiveCtrl,看起来有点笨拙

是否有另一种方法可以在没有链接功能的情况下从指令的控制器访问 require-ed 控制器?

您必须使用link 函数来获取require-ed 控制器,但您不需要使用作用域将控制器的引用传递给您自己的控制器。相反,将其直接传递给您自己的控制器:

.directive('fooDirective', function () {
  return {

    require: ["fooDirective", "^parentDirective"],

    link: function link(scope, element, attrs, ctrls) {
      var me     = ctrls[0],
          parent = ctrls[1];

      me.parent = parent;
    },
    controller: function(){...},
  };
});

不过要小心,因为控制器在 link 之前运行,所以在控制器内 this.parentundefined,直到 link 函数运行之后。如果您需要确切知道什么时候发生,您总是可以使用控制器函数将 parentDirective 控制器传递给:

link: function link(scope, element, attrs, ctrls) {
  //...

  me.registerParent(parent);
},
controller: function(){
  this.registerParent = function(parent){
    //...
  }
}

有一种方法可以避免使用$scope访问父控制器,但你必须使用link功能。 Angular 的文档 says:

Require

Require another directive and inject its controller as the fourth argument to the linking function...

选项 1

由于 controllerAs 在控制器的 scope 中创建了命名空间,因此您可以在 link 函数中访问此命名空间,并将所需的控制器直接放在 childDirective 的控制器上使用 $scope。然后代码将如下所示。

angular.module('app', []).
  controller('parentController', function() {
    this.doSomething = function() {
      alert('parent');
    };
  }).
  controller('childController', function() {
    this.click = function() {
      this.parentDirectiveCtrl.doSomething();
    }
  }).
  directive('parentDirective', function() {
    return {
      controller: 'parentController'
    }
  }).
  directive('childDirective', function() {
    return {
      template: '<button ng-click="controller.click()">Click me</button>',
      link: function link(scope, element, attrs, parentDirectiveCtrl) {
        scope.controller.parentDirectiveCtrl = parentDirectiveCtrl;
      },
      controller: 'childController',
      controllerAs: 'controller',
      bindToController: true,
      require: '^parentDirective'
    }
  });

笨蛋:

http://plnkr.co/edit/YwakJATaeuvUV2RBDTGr?p=preview

选项 2

我通常根本不在指令中使用控制器,而是通过服务共享功能。如果您不需要弄乱父指令和子指令的隔离范围,只需向它们注入相同的服务并将所有功能都投入使用。

angular.module('app', []).
  service('srv', function() {
    this.value = '';
    this.doSomething = function(source) {
      this.value = source;
    }
  }).
  directive('parentDirective', ['srv', function(srv) {
    return {
      template: '<div>' + 
                  '<span ng-click="srv.doSomething(\'parent\')">Parent {{srv.value}}</span>' +
                  '<span ng-transclude></span>' +
                '</div>',
      transclude: true,
      link: function(scope) { scope.srv = srv; }
    };
  }]).
  directive('childDirective', ['srv', function(srv) {
    return {
      template: '<button ng-click="srv.doSomething(\'child\')">Click me</button>',
      link: function link(scope) { scope.srv = srv; }
    }
  }]);

笨蛋

http://plnkr.co/edit/R4zrXz2DBzyOuhugRU5U?p=preview

好问题! Angular 让你通过 "parent" 控制器。您已经将它作为 link 函数的参数。这是第四个参数。为了简单起见,我将其命名为 ctrl。您不需要您拥有的 scope.parentDirectiveCtrl=parentDirectiveCtrl 行。

.directive('fooDirective', function () {
  return {
// Passing in parentDirectiveCtrl into $scope here
link: function link(scope, element, attrs, ctrl) {
  // What you had here is not required.
},
controller: 'FooController',
controllerAs: 'controller',
bindToController: true,
require: '^parentDirective'};});

现在在你的父控制器上你有

this.doSomething=function(). 

您可以访问此 doSomething 作为

ctrl.doSomething().