I read document from AngualrJS : https://docs.angularjs.org/guide/component
And when I am reading to "Example of a component tree" section, I got confused about how a component tree's loading works, because there is nowhere to find the loading order.
How angular find the root directive and nested directive (may be in a template)? and Which component should start work first? I mean, If a nested component() is called earlier than its directive's appearance, will it be called later when its directive appears? How angular knows the appropriate component to call when a directive/template load? Or just iterate all components method? Or load all components first, then according index.html to form a component hierarchy, then call it properly?
Is there anybody kindly explain? thanks a lot!
Thanks estus!, your anwser is really helpful! According to AngularJS : How does the HTML compiler arrange the order for compiling? and Pete Bacon Darwin's example :
Just in my opinion:
Angular call all components comiple() method first to complete whole template loading, then call their controller() methods regard to directives hierarchy.
And this comes from : How directives are compiled
It's important to note that Angular operates on DOM nodes rather than
strings. Usually, you don't notice this restriction because when a
page loads, the web browser parses HTML into the DOM automatically.
HTML compilation happens in three phases:
$compile traverses the DOM and matches directives.
If the compiler finds that an element matches a directive, then the directive is added to the list of directives that match the DOM
element. A single element may match multiple directives.
Once all directives matching a DOM element have been identified, the compiler sorts the directives by their priority. Each
directive's compile functions are executed. Each compile function
has a chance to modify the DOM. Each compile function returns a
link function. These functions are composed into a "combined" link
function, which invokes each directive's returned link function.
$compile links the template with the scope by calling the combined linking function from the previous step. This in turn will
call the linking function of the individual directives, registering
listeners on the elements and setting up $watchs with the
scope as each directive is configured to do.
Related
I am very new to angularjs. I have little bit confusion with link and compile usage in directives. Can anyone please tell me in which scenarios we have to use link and compile.
What is the difference between compile and link function in angularjs
Already answered on stack overflow and has an excellent explanation
The compile phase
When the DOM is loaded Angular starts the compile phase, where it traverses the markup top-down, and calls compile on all directives. Graphically, we could express it like so:
An image illustrating the compilation loop for children
It is perhaps important to mention that at this stage, the templates the compile function gets are the source templates (not instance template).
The link phase
DOM instances are often simply the result of a source template being rendered to the DOM, but they may be created by ng-repeat, or introduced on the fly.
Whenever a new instance of an element with a directive is rendered to the DOM, the link phase starts.
In this phase, Angular calls controller, pre-link, iterates children, and call post-link on all directives, like so:
Below links will give you clear idea for compile vs link.
Angular directives - when and how to use compile, controller, pre-link and post-link
http://odetocode.com/blogs/scott/archive/2014/05/28/compile-pre-and-post-linking-in-angularjs.aspx
I have read that DOM manipulation in angular should be done in the compile function of a directive, and not in the pre-link/post-link/controller. The compile function does not have access to the scope.
My problem is that I want to do DOM manipulation that is dependent on scope variables. For example, I have a list that I am passing into the directive. Within the directive, I am creating a custom select with the list items within it. Where is the right place to manipulate the DOM in this case?
Note that I am not using ng-repeat - I have found it very slow when the list becomes large.
I don't know where you have read "DOM manipulation in angular should be done in the compile function of a directive". That contradicts the advice of the AngularJS team.
Creating a Directive that Manipulates the DOM
Directives that want to modify the DOM typically use the link option to register DOM listeners as well as update the DOM.
-- AngularJS Developer Guide - Directives - DOM Manipulation
The built-in directives, ng-repeat, ng-if, ng-when, etc. all do their DOM manipulation in the link function.
compile
The compile function deals with transforming the template DOM. Since most directives do not do template transformation, it is not used often.
-- AngularJS $compile Service API Reference -- compile
I use ui-router to create routes with multiple HTML pages.
I have custom "target" directives within these pages that use $state.current in various ways.
But I also have other custom "lookup" directives in other states which load these HTML "templates", find these "target" directives, compile them and insert them into the DOM.
The problem I am having is that when the HTML content is compiled in these second directives, $state.current obviously refers to whatever state the application is in when it is compiled, whereas I would like the directive to compile as if it was in its "native" state.
Is there any (easy-ish!) way to get a reference to the target directive's "native" state? i.e. the state connected to the .HTML file which the directive is in? Is there a method (angular, jquery, native js or anything else) to get from the directive to the HTML template file? Then I could do a reverse lookup on the state objects. element.ownerDocument can get the URL of the current state, but not the HTML file of the template.
Alternatively, if the second directive had a reference to the "target" state, how should I modify the "target" directive so that it takes a state reference when it is compiled in both scenarios? Something in the compile function perhaps?? - but the docs don't seem to cover this kind of use case... I could do with a pointer in the right direction.
I hope that all makes sense. I have looked around for similar answers, but I guess this is an unusual use case? I'll knock up a Plunker shortly to help illustrate...
When you compile HTML using $compile, you pass in a scope object. Instead of using $state.current within the directive, could you attach the "state" you need to the scope object that you're passing in?
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