如何从另一个控制器访问require-d控制器?

时间:2015-08-07 20:37:44

标签: javascript angularjs angular-directive

我有一个类似于此的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控制器而不使用链接功能?

3 个答案:

答案 0 :(得分:3)

您必须使用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(){...},
  };
});

但是要小心,因为控制器在链接之前运行,所以在控制器this.parent内是undefined,直到链接功能运行之后。如果您需要确切知道何时发生这种情况,您始终可以使用控制器功能将parentDirective控制器传递给:

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

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

答案 1 :(得分:1)

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

  

<强>需要

     

需要另一个指令并将其控制器作为第四个注入   链接函数的参数......

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

<强> Plunker

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

<强> Plunker

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

答案 2 :(得分:0)

好问题! Angular让你通过&#34; parent&#34;控制器。您已将其作为链接功能的参数。这是第四个参数。为简单起见,我将其命名为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().