2

I'm writing an angular "tab" directive which needs to communicate with a parent "tabs" directive by sending a reference to itself to the parent.

I am trying to keep my code in the directive's controller, not the link function, because I'm not really doing anything with DOM.

The problem is that if i use {require: '^tabs'} i can get a copy of the required directive's controller like this..

link: function(scope, element, attr, ctrls) {
    var controller = ctrls[0];
}

but how would I do this inside the directive's controller function?

1
  • I believe you have to do this in the link, as the controller lookup done by require searched the DOM for directives and their respective controllers. Commented Mar 1, 2016 at 17:35

2 Answers 2

1

This is always a fun problem for me. I like to think that I am playing on the wild side with my solution to this common case.

First, I take a step back to the controllerAs view syntax as suggested in the the angular style guide (https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#controlleras-controller-syntax)

Using this syntax you can define your directive as:

    var directive = {
        require: '^myParentDirective',
        restrict: 'EA',
        controller: 'MyController as myCtrl',
        templateUrl: 'super/awesome/app/my/my.directive.html',
        scope: {
            myProp: '='
        }, // isolate scope
        link: link
    };

    function link(scope, element, attr, myParentCtrl) {

        scope.myCtrl.myParent = myParentCtrl;

    }

The catch (there's always a catch):

Remember that a directive's controller is constructed before the link function is invoked. So you cannot expect the myParent property to be resolved in the code executed during the controller's construction.

function MyController($scope) {

    var _self = this;

    _self.myParent.register(_self); // myParent is not defined

}

Instead wait until you are sure myParent is resolved

function MyController(scope) {

    var _self = this;

    _self.initialize = initialize;

    return;

    function initialize() {

        _self.myParent.register(_self); // myParent might be defined

    }

}

then do something like

function link(scope, element, attr, myParentCtrl) {

    scope.myCtrl.myParent = myParentCtrl;

    scope.myCtrl.initialize();

}

Let me know if this helps, is off base, or if you need more clarification.

(Also, please excuse syntax errors)

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, that is what I am trying to do. The only difference is that I need to pass $scope in the register method, not _self becuse the parent directory need access to scope methods and $destroy etc. Unless I have misunderstood.
1

Generally, if you need to share data between controllers, you can create a factory/service to store the data, and inject the service in those controllers. The data set in the service will be singleton.

angular.module('myApp', [])
  .factory('myService', function() {
    var myData;
    return {
      getData: function () {
        return this.myData;
      },
      setData: function (data) {
        this.myData = data;
      }
    }
  .controller('controller1', function(myService) {
  })
  .controller('controller2', function(myService) {
  })
});

If the child directive has no scope data, you can also set the directive scope to false and it will inherit the scope of the parent controller.

angular.module('myApp', [])
.directive('myDirective', function() {
  return {
    restrict: 'E',
    scope: false,
    controller: 'controller1'
  };
});

1 Comment

Thanks dannielum, but for my current problem I don't think a singleton would work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.