In trying to get a grasp on creating my own AngularJS directives, I have an example that does everything I need, but realize that in borrowing from various examples, I now can create functionality for the directive's view in both the controller as well as the link.
It seems that I could get rid of the controller all together and just put everything into link, or is there something that I can do with the controller that I can't do with link?
http://jsfiddle.net/edwardtanguay/gxr49h96/6
.directive('itemMenu', function () {
var controller = function ($scope) {
var vm = this;
vm.addItem = function () {
$scope.add();
vm.items.push({
'kind': 'undefined',
'firstName': 'Joe',
'lastName': 'Newton',
'age': Math.floor(Math.random() * 60) + 20
});
};
// DOES THE SAME AS THE FUNCTION DEFINED BELOW IN LINK
// $scope.convertToInternal = function(item) {
// item.internalcode = 'X0000';
// item.kind = 'internal';
// };
};
return {
restrict: 'A',
scope: {
item: '=',
add: '&'
},
controller: controller,
controllerAs: 'vm',
bindToController: true,
template: '<div ng-include="getTemplateUrl()"></div>',
link: function (scope, element, attrs) {
scope.getTemplateUrl = function () {
switch (scope.item.kind) {
case 'external':
return 'itemMenuTemplateExternal';
case 'internal':
return 'itemMenuTemplateInternal';
default:
return 'itemMenuTemplateUndefined';
}
};
scope.convertToInternal = function(item) {
item.internalcode = 'X0000';
item.kind = 'internal';
};
},
};
})
You may find a lot of watery rants about controller vs link, most of them contain the information from $compile service documentation.
Answering the question directly,
controllers from other modules/files can be plugged into the directive via Angular DI with
controller: 'Controller'
controller
can be injected with dependencies whilelink
has fixed arguments list of and gets by with directive's dependenciescontroller
kicks in beforelink
, so it can prepare the scope for linking or recompile the element on some condition ASAPcontroller function has
this
, its code appearance complies to other OOP-like ES5 code, and the methods can be easily transferred between other code parts, e.g.service
service or third-party codeas the result, controllers are suited to be defined as ES2015 or TS classes.
directive's controller can be
require
d by child directive and provides convenient one-way interaction between those twocontroller
makes use ofbindToController: true
+controllerAs: 'vm'
and implements$scope.vm
recipe (particularly useful to fight JS prototypal inheritance) while keepingthis
syntaxbindToController
object value provides attribute bindings for inheritedscope: true
scope, no more$attr.$observe
bindToController
object value provides further granularity for isolated scope. If there are certain attributes that should be bound to the controller and accessed withrequire
, it can be done nowWhich code goes to
controller
and which tolink
is more delicate question.It is conventional to use Angular controllers as view models, as in MVVM (hence the
controllerAs: 'vm'
convention), so if there is a job for controllers (i.e. binding the services to scope values or setting up scope watchers) give it to them, leave the rest tolink
.Since
$attrs
,$element
and$transclude
local dependencies should be injected into controller explicitly, the one may consider it a sign to skip them ($scope
should be injected too for$scope.$
methods, but we will just ignore this fact).There are some non-religious concerns about the job that should be done by
link
and not bycontroller
.require
d controllers aren't available in controller itself, so this kind of directive interaction takes place inlink
. Sincecontroller
launches at earlier compilation phase thanlink
, bound attribute values won't be interpolated yet, so the code that depends on these scope values goes tolink
. The same applies to other DOM-related code, it goes tolink
for a reason.It is mostly the matter of proper code style and not real necessity. As of the code in the example, all
scope
stuff is controller-friendly, I don't think thatlink
should be there at all.