I need to perform some operations on scope and the template. It seems that I can do that in either the link
function or the controller
function (since both have access to the scope).
When is it the case when I have to use link
function and not the controller?
angular.module('myApp').directive('abc', function($timeout) {
return {
restrict: 'EA',
replace: true,
transclude: true,
scope: true,
link: function(scope, elem, attr) { /* link function */ },
controller: function($scope, $element) { /* controller function */ }
};
}
Also, I understand that link
is the non-angular world. So, I can use $watch
, $digest
and $apply
.
What is the significance of the link
function, when we already had controller?
After my initial struggle with the link
and controller
functions and reading quite a lot about them, I think now I have the answer.
First lets understand,
How do angular directives work in a nutshell:
We begin with a template (as a string or loaded to a string)
var templateString = '<div my-directive>{{5 + 10}}</div>';
Now, this templateString
is wrapped as an angular element
var el = angular.element(templateString);
With el
, now we compile it with $compile
to get back the link function.
var l = $compile(el)
Here is what happens,
$compile
walks through the whole template and collects all the directives that it recognizes.link
functions are collected.link
functions are wrapped in a new link
function and returned as l
.Finally, we provide scope
function to this l
(link) function which further executes the wrapped link functions with this scope
and their corresponding elements.
l(scope)
This adds the template
as a new node to the DOM
and invokes controller
which adds its watches to the scope which is shared with the template in DOM.
Comparing compile vs link vs controller :
Every directive is compiled only once and link function is retained for re-use. Therefore, if there's something applicable to all instances of a directive should be performed inside directive's compile
function.
Now, after compilation we have link
function which is executed while attaching the template to the DOM. So, therefore we perform everything that is specific to every instance of the directive. For eg: attaching events, mutating the template based on scope, etc.
Finally, the controller is meant to be available to be live and reactive while the directive works on the DOM
(after getting attached). Therefore:
(1) After setting up the view[V] (i.e. template) with link. $scope
is our [M] and $controller
is our [C] in M V C
(2) Take advantage the 2-way binding with $scope by setting up watches.
(3) $scope
watches are expected to be added in the controller since this is what is watching the template during run-time.
(4) Finally, controller
is also used to be able to communicate among related directives. (Like myTabs
example in https://docs.angularjs.org/guide/directive)
(5) It's true that we could've done all this in the link
function as well but its about separation of concerns.
Therefore, finally we have the following which fits all the pieces perfectly :
The difference between link
and controller
comes into play when you want to nest directives in your DOM and expose API functions from the parent directive to the nested ones.
From the docs:
Best Practice: use controller when you want to expose an API to other directives. Otherwise use link.
Say you want to have two directives my-form
and my-text-input
and you want my-text-input
directive to appear only inside my-form
and nowhere else.
In that case, you will say while defining the directive my-text-input
that it requires a controller from the parent
DOM element using the require argument, like this: require: '^myForm'
. Now the controller from the parent element will be injected
into the link
function as the fourth argument, following $scope, element, attributes
. You can call functions on that controller and communicate with the parent directive.
Moreover, if such a controller is not found, an error will be raised.
There is no real need to use the link
function if one is defining the controller
since the $scope
is available on the controller
. Moreover, while defining both link
and controller
, one does need to be careful about the order of invocation of the two (controller
is executed before).
However, in keeping with the Angular way, most DOM manipulation and 2-way binding using $watchers
is usually done in the link
function while the API for children and $scope
manipulation is done in the controller
. This is not a hard and fast rule, but doing so will make the code more modular and help in separation of concerns (controller will maintain the directive
state and link
function will maintain the DOM
+ outside bindings).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With