As far as I know that basically scope is an instance of a controller.
Every time I declare a controller scope will be available for that controller.
But then why directive has scope in link function ?
I didn't declare any controller for the directive.
Then why link function has scope ? Any Idea ?
From the doc:
scope:
The scope to be used by the directive for registering watches.
You may also be interested to see the differences between $scope and scope.
All directives have a scope associated with them. They use this scope for accessing data/methods inside the template and link function. By default, unless explicitly set, directives don’t create their own scope. Therefore, directives use their parent scope ( usually a controller ) as their own.
However, AngularJS allows us to change the default scope of directives by passing a configuration object known as directive definition object. A directive definition object –– let’s call it as DDO –– is a simple JavaScript object used for configuring the directive’s behaviour,template..etc. Check out AngularJS docs about DDO.
So, we can use scope inside linking function to work with parent scope, child scope or isolated scope.
You may visit this for detailed information about scope inside directive.
You can share the data between controller and linking function.
Sometimes we would like to access that same data in both controller and link functions in Angular directive. Usually we add this data to the scope object. This has certain problems, for example exposing it to any child scope. Add the shared properties to the controller instance itself and access in the link function.
You may also be interested in what is need of link function?
A directive is Angular's way of defining 'components': you specify how its markup looks and how it behaves before, during and after being rendered. The link functions allow you to hook up events to the DOM element before or after it gets 'linked' (see also: pre-link and post-link methods). When these events are fired you might want to change some of the variables within the scope, and that's why you have access to it within the link functions.
Related
I'd like to access a function from the parent => parent controller inside my directive (with the controllerAs notation). I'm using angular 1.3.14
I have the following structure:
Controller (with save function)
(Child) controller
Directive with a template (and isolated scope). Inside this template I have a button which should call the save function from the parent (parent) controller.
I don't want to call $scope.$parent.$parent.save(...)
Does anyone has an idea?
Thanks in advance.
Use just $scope.save().
In Angular there is scope hierarchy and by calling $scope.save() directive will look in directive's scope, if there is no save() method, it will look in parent's scope and so on.
One condition is to don't have isolated scope for directive.
There is no good way to do this other than passing the desired function into the directive. This is what using & in an isolated scope declaration is for.
https://docs.angularjs.org/guide/directive
Of course there are easier ways if the function is just a utility function. You could just register a filter. But if you want the child directive to alter the state of the parent controller at some event then using & is the best solution.
If you need the child directive to pass arguments to the function that is being passed to it then you are going to need to use the feature associated with this sentence in the above documentation:
This is specified in the directive by calling close({message: 'closing
for now'}). Then the local variable message will be available within
the on-close expression.
I have two scenarios:
A function defined in a controller is called from a directive (see plunk).
The directive includes a '&' scope restriction to relate the controller and directive functions. If you click on the text, the element click event is triggered in the directive and the controller function is called. $scope.$apply() is used to notify AngularJS of the click event and refresh the value of var on the screen.
A function defined in a directive is called from a controller (see plunk).
The directive doesn't have any scope restriction, meaning that $scope in the controller and scope in the directive are shared. I defined func1() in the directive that can be called from the controller (try clicking on the text), however it seems intrusive as the controller needs to know the name of the function.
Is there a way to define func1() in such a way that the function name is declared in the directive div, similar to scenario 1?
Both options are possible and acceptable depending on how you are building the component.
Option 1 - Controllers should register listeners/callbacks and set attributes on directives (when using isolated scope - which i recommend). Controllers should not call a directives function but instead should change an attribute that has been bound on the directive. The directive if setup correctly should be watching this attribute and update accordingly.
Directives should not know who their controllers are in my opinion, it promotes decoupled code. Instead, controllers should be setting callback functions that directives can invoke at the appropriate time (i.e. letting the controller know something was clicked, selected, deleted, swiped, etc...)
Option 2 - Is acceptable to me when you are building a web component that provides the structure and behavioral logic but does not define the actual individual components UI (not including a possible skeleton UI). For example a list directive. The individual list may not be defined in the directive but "plugged in" for each context or use, giving us a more modular and reusable component. It does require us to know some things about the directive. It also requires that we modify the transclusion function to use the directives scope on the transcluded content instead of the original controllers scope. For an example you can checkout a list component I made as an example to this point.
http://github.com/Spidy88/ng-web-components
A snippet of text from this html page. The sf-list directive is an isolated scope directive that defines a lists behavior. However we can still define what each individual list item looks like with modified transclusion. It relies on us to call selectItem though in order to trigger selection behavior on the list.
<sf-list items="ctrl.emails" listener="ctrl.adapter">
<div class="list-item email" ng-click="selectItem(item)" ng-repeat="item in items track by item.id">
<div class="from">{{ item.from }}:</div>
<div class="subject">{{ item.subject }}</div>
</div>
</sf-list>
According to the Angular docs:
Scope is the glue between application controller and the view. During the template linking phase the directives set up $watch expressions on the scope. The $watch allows the directives to be notified of property changes, which allows the directive to render the updated value to the DOM.
Now my Question is : if my function is not connected to the view, should we use $scope or not?
I assume that you mean if you should do $scope.functionName = function(), even if the function isn't connected to the view.
No you shouldn't, why would you expose a function to the view, which isn't needed to the view? Also you get a better overview which functions is internally when only using function funcName().
You shouldn't use the $scope to declare every function you are using, especially if it's not connected to the view.
However, there are some cases you need to use the $scope in a function not connected to view, for example if you want to emit/receive/broadcast a message on the scope tree or access something on a parent scope (although it's not necessarly a good practice).
Some places seem to use the controller function for directive logic and others use link. The tabs example on the angular homepage uses controller for one and link for another directive. What is the difference between the two?
I'm going to expand your question a bit and also include the compile function.
compile function - use for template DOM manipulation (i.e., manipulation of tElement = template element), hence manipulations that apply to all DOM clones of the template associated with the directive. (If you also need a link function (or pre and post link functions), and you defined a compile function, the compile function must return the link function(s) because the 'link' attribute is ignored if the 'compile' attribute is defined.)
link function - normally use for registering listener callbacks (i.e., $watch expressions on the scope) as well as updating the DOM (i.e., manipulation of iElement = individual instance element). It is executed after the template has been cloned. E.g., inside an <li ng-repeat...>, the link function is executed after the <li> template (tElement) has been cloned (into an iElement) for that particular <li> element. A $watch allows a directive to be notified of scope property changes (a scope is associated with each instance), which allows the directive to render an updated instance value to the DOM.
controller function - must be used when another directive needs to interact with this directive. E.g., on the AngularJS home page, the pane directive needs to add itself to the scope maintained by the tabs directive, hence the tabs directive needs to define a controller method (think API) that the pane directive can access/call. For a more in-depth explanation of the tabs and pane directives, and why the tabs directive creates a function on its controller using this (rather than on $scope), please see 'this' vs $scope in AngularJS controllers.
In general, you can put methods, $watches, etc. into either the directive's controller or link function. The controller will run first, which sometimes matters (see this fiddle which logs when the ctrl and link functions run with two nested directives). As Josh mentioned in a comment, you may want to put scope-manipulation functions inside a controller just for consistency with the rest of the framework.
As complement to Mark's answer, the compile function does not have access to scope, but the link function does.
I really recommend this video; Writing Directives by Misko Hevery (the father of AngularJS), where he describes differences and some techniques. (Difference between compile function and link function at 14:41 mark in the video).
running code before Compilation : use controller
running code after Compilation : use Link
Angular convention : write business logic in controller and DOM manipulation in link.
Apart from this you can call one controller function from link function of another directive.For example you have 3 custom directives
<animal>
<panther>
<leopard></leopard>
</panther>
</animal>
and you want to access animal from inside of "leopard" directive.
http://egghead.io/lessons/angularjs-directive-communication will be helpful to know about inter-directive communication
compile function -
is called before the controller and link function.
In compile function, you have the original template DOM so you can make changes on original DOM before AngularJS creates an instance of it and before a scope is created
ng-repeat is perfect example - original syntax is template element, the repeated elements in HTML are instances
There can be multiple element instances and only one template element
Scope is not available yet
Compile function can return function and object
returning a (post-link) function - is equivalent to registering the linking function via the link property of the config object when the compile function is empty.
returning an object with function(s) registered via pre and post properties - allows you to control when a linking function should be called during the linking phase. See info about pre-linking and post-linking functions below.
syntax
function compile(tElement, tAttrs, transclude) { ... }
controller
called after the compile function
scope is available here
can be accessed by other directives (see require attribute)
pre - link
The link function is responsible for registering DOM listeners as well as updating the DOM. It is executed after the template has been cloned. This is where most of the directive logic will be put.
You can update the dom in the controller using angular.element but this is not recommended as the element is provided in the link function
Pre-link function is used to implement logic that runs when angular js has already compiled the child elements but before any of the child element's post link have been called
post-link
directive that only has link function, angular treats the function as a post link
post will be executed after compile, controller and pre-link funciton, so that's why this is considered the safest and default place to add your directive logic
Some places seem to use the controller function for directive logic and others use link. The tabs example on the angular homepage uses controller for one and link for another directive. What is the difference between the two?
I'm going to expand your question a bit and also include the compile function.
compile function - use for template DOM manipulation (i.e., manipulation of tElement = template element), hence manipulations that apply to all DOM clones of the template associated with the directive. (If you also need a link function (or pre and post link functions), and you defined a compile function, the compile function must return the link function(s) because the 'link' attribute is ignored if the 'compile' attribute is defined.)
link function - normally use for registering listener callbacks (i.e., $watch expressions on the scope) as well as updating the DOM (i.e., manipulation of iElement = individual instance element). It is executed after the template has been cloned. E.g., inside an <li ng-repeat...>, the link function is executed after the <li> template (tElement) has been cloned (into an iElement) for that particular <li> element. A $watch allows a directive to be notified of scope property changes (a scope is associated with each instance), which allows the directive to render an updated instance value to the DOM.
controller function - must be used when another directive needs to interact with this directive. E.g., on the AngularJS home page, the pane directive needs to add itself to the scope maintained by the tabs directive, hence the tabs directive needs to define a controller method (think API) that the pane directive can access/call. For a more in-depth explanation of the tabs and pane directives, and why the tabs directive creates a function on its controller using this (rather than on $scope), please see 'this' vs $scope in AngularJS controllers.
In general, you can put methods, $watches, etc. into either the directive's controller or link function. The controller will run first, which sometimes matters (see this fiddle which logs when the ctrl and link functions run with two nested directives). As Josh mentioned in a comment, you may want to put scope-manipulation functions inside a controller just for consistency with the rest of the framework.
As complement to Mark's answer, the compile function does not have access to scope, but the link function does.
I really recommend this video; Writing Directives by Misko Hevery (the father of AngularJS), where he describes differences and some techniques. (Difference between compile function and link function at 14:41 mark in the video).
running code before Compilation : use controller
running code after Compilation : use Link
Angular convention : write business logic in controller and DOM manipulation in link.
Apart from this you can call one controller function from link function of another directive.For example you have 3 custom directives
<animal>
<panther>
<leopard></leopard>
</panther>
</animal>
and you want to access animal from inside of "leopard" directive.
http://egghead.io/lessons/angularjs-directive-communication will be helpful to know about inter-directive communication
compile function -
is called before the controller and link function.
In compile function, you have the original template DOM so you can make changes on original DOM before AngularJS creates an instance of it and before a scope is created
ng-repeat is perfect example - original syntax is template element, the repeated elements in HTML are instances
There can be multiple element instances and only one template element
Scope is not available yet
Compile function can return function and object
returning a (post-link) function - is equivalent to registering the linking function via the link property of the config object when the compile function is empty.
returning an object with function(s) registered via pre and post properties - allows you to control when a linking function should be called during the linking phase. See info about pre-linking and post-linking functions below.
syntax
function compile(tElement, tAttrs, transclude) { ... }
controller
called after the compile function
scope is available here
can be accessed by other directives (see require attribute)
pre - link
The link function is responsible for registering DOM listeners as well as updating the DOM. It is executed after the template has been cloned. This is where most of the directive logic will be put.
You can update the dom in the controller using angular.element but this is not recommended as the element is provided in the link function
Pre-link function is used to implement logic that runs when angular js has already compiled the child elements but before any of the child element's post link have been called
post-link
directive that only has link function, angular treats the function as a post link
post will be executed after compile, controller and pre-link funciton, so that's why this is considered the safest and default place to add your directive logic