Friday, November 22, 2013

Get current directive controller in AngularJS

You can pass information and functionalut in to Directives in a number fo ways. One of those ways is the controller. Most directives will have a controller associated with it which acts as a way to organize the logic you need to call upon and is a good way to add functionality to the scope. Directives can also inherit a controller from higher up in the chain which is great, however it may make it harder to use the controller you define. For an exmaple:


var aControl = function() {};
var bControl = function() {};

var a = function() {
	return {
		link: function(scope, element, attrs, ctrl) {
			// ctrl references aControl
		},
		controller: aControl
	};
};

var b = function() {
	return {
		require: '^a',
		link: function(scope, element, attrs, ctrl) {
			// ctrl references aControl

			// but how do I get a reference to bControl??
		},
		controller: bControl
	};
};


So your control will be passed in unless you define require as can be seen in AngularJS code:


directive.require = directive.require || (directive.controller && directive.name);

So how do you get a handle to the current control? Well looking through the code we can see that when we have a directive on an element it will be attached:

$element.data('$' + directive.name + 'Controller', controllerInstance);

So to get at the current controller we just have to check the data on the current element like so:

var b = function() {
	var myDirectiveName = 'b';

	return {
		require: '^a',
		link: function(scope, element, attrs, ctrl) {
			var myParentCtrl = ctrl;

			var myCurrentControl = element.data('$' + myDirectiveName + 'Controller');
		},
		controller: bControl
	};
};

6 comments:

  1. NIce - works! Great job figuring that out.

    I'm wondering how to do this less "hackily" - no offense intended.

    Have you heard of other solutions?

    ReplyDelete
  2. The proper way to do this: https://gist.github.com/justindujardin/19767e8ea72ccd2f41d3

    ReplyDelete
    Replies
    1. That is the proper way to get it if you know the name assigned to the directive.

      I was trying to solve this problem in the same context as my previous post where I provide the factory but a user could register the directive under a different name. In that case you can't have the name under require without the user providing it first, or you need to do it within the link function (as above) and grab the name from the directive object (instead I just gave the name in a variable in the example).

      Delete
  3. Just do: element.controller(myControllerName)

    ReplyDelete
    Replies
    1. correction: element.controller(myDirectiveName)

      Delete