To understand the difference between compile and link, we need to understand how Angular bootstrap the app, that is why i combined these 2 topics.
To bootstrap any angular app, it is just writing a "ng-app" tag in the HTML and that is all, but behind the scene what happens, we don't know. I tried to explore it in detail and that is what i came up with.
Before we go into the detail, please read startup section from Angular site (http://docs.angularjs.org/guide/concepts) -
Here is my understanding how it works -
Lets try to bootstrap the application manually, instead of relying upon Angular. For this we will have to wait for application's DOM to get ready. I have bootstrap code in the window.onload and here is the code with the detail comments -
Here is the HTML code -
<body ng-controller="Demo">
Name: <input ng-model="name" />
<div>
Hello <span ng-bind="name"></span>
</div>
<ul>
<li ng-repeat="i in [1,2,3]">{{i}}</li>
</ul>
</body>
Here is the JavaScript -
var myApp = angular.module('myApp', []);
function Demo($scope) {}
window.onload = function () {
var $rootElement = angular.element(window.document);
var modules = [
'ng',
'myApp',
function($provide){
$provide.value('$rootElement', $rootElement);
}
];
var $injector = angular.injector(modules);
var $compile = $injector.get('$compile');
var compositeLinkFn = $compile($rootElement);
var $rootScope = $injector.get('$rootScope');
compositeLinkFn($rootScope);
$rootScope.$apply();
}
Explaination of Code -
var $rootElement = angular.element(window.document);
wait for DOM to load;
get the root of the document,normally location of ngapp, in our case just the root element
var modules = [..];
get list of modules
Inside module the 1st module we mentioned is - 'ng' which os inbuilt module of Angular. for manual bootstrap we need to mention it. If we won't mention it we will get this error -Unknown provider: $compileProvider <- compile="" p="">
Next i mentioned myApp, which is the module i wanted to bootstrap
'myApp'
After this there is 3rd inline module, just for demonstration purpose.
function($provide){
$provide.value('$rootElement', $rootElement);
}
var $injector = angular.injector(modules);
Get the rootinjector of the application. There can only be one injector instance per application and not per module.
Above line creates the injector and returns its object.
var $compile = $injector.get('$compile')
It returns the compile service, which actually compile the code. If you read the article on Angular Overview from Angular official site, then it is the same compile service it was talking about.
compile service traverse the DOM and get the directives and returns the link fn collection.
var compositeLinkFn = $compile($rootElement);
We get the linking function using compile service.
var $rootScope = $injector.get('$rootScope');
get the rootscope. It is the same root element where we write the ng-app tag to make it an Angular app.
compositeLinkFn($rootScope);
Call the link function, that is where actual mapping of view with the original object happens.
$rootScope.$apply();
command Angular to render the view for you.
The above code demonstrate how Angular bootstrap the app, But it doesn't give any details on compile Vs link, Which is the topic of this article. Well Lets talk about it now.
Compile - It works on template. Its like adding a class element in to the DOM.
Link - It works on instances.
The concept of compile and link comes from C, where we first compile the code and then link it to actually execute it. The process is very much same in Angular as well.
In Angular not every directive will be able to demonstrate it, but "repeate" directive shows the difference very clearly.
To understand the difference lets try to debug the above code. Attach the debugger at line 2, 16 and 20. Here is the screent shot what i see when i am at line 2 -
->
To bootstrap any angular app, it is just writing a "ng-app" tag in the HTML and that is all, but behind the scene what happens, we don't know. I tried to explore it in detail and that is what i came up with.
Before we go into the detail, please read startup section from Angular site (http://docs.angularjs.org/guide/concepts) -
Here is my understanding how it works -
Lets try to bootstrap the application manually, instead of relying upon Angular. For this we will have to wait for application's DOM to get ready. I have bootstrap code in the window.onload and here is the code with the detail comments -
Here is the HTML code -
<body ng-controller="Demo">
Name: <input ng-model="name" />
<div>
Hello <span ng-bind="name"></span>
</div>
<ul>
<li ng-repeat="i in [1,2,3]">{{i}}</li>
</ul>
</body>
Here is the JavaScript -
var myApp = angular.module('myApp', []);
function Demo($scope) {}
var $rootElement = angular.element(window.document);
var modules = [
'ng',
'myApp',
function($provide){
$provide.value('$rootElement', $rootElement);
}
];
var $injector = angular.injector(modules);
var $compile = $injector.get('$compile');
var compositeLinkFn = $compile($rootElement);
var $rootScope = $injector.get('$rootScope');
compositeLinkFn($rootScope);
$rootScope.$apply();
}
Explaination of Code -
var $rootElement = angular.element(window.document);
wait for DOM to load;
get the root of the document,normally location of ngapp, in our case just the root element
var modules = [..];
get list of modules
Inside module the 1st module we mentioned is - 'ng' which os inbuilt module of Angular. for manual bootstrap we need to mention it. If we won't mention it we will get this error -Unknown provider: $compileProvider <- compile="" p="">
Next i mentioned myApp, which is the module i wanted to bootstrap
'myApp'
After this there is 3rd inline module, just for demonstration purpose.
function($provide){
$provide.value('$rootElement', $rootElement);
}
var $injector = angular.injector(modules);
Get the rootinjector of the application. There can only be one injector instance per application and not per module.
Above line creates the injector and returns its object.
var $compile = $injector.get('$compile')
It returns the compile service, which actually compile the code. If you read the article on Angular Overview from Angular official site, then it is the same compile service it was talking about.
compile service traverse the DOM and get the directives and returns the link fn collection.
var compositeLinkFn = $compile($rootElement);
We get the linking function using compile service.
var $rootScope = $injector.get('$rootScope');
get the rootscope. It is the same root element where we write the ng-app tag to make it an Angular app.
compositeLinkFn($rootScope);
Call the link function, that is where actual mapping of view with the original object happens.
$rootScope.$apply();
command Angular to render the view for you.
The above code demonstrate how Angular bootstrap the app, But it doesn't give any details on compile Vs link, Which is the topic of this article. Well Lets talk about it now.
Compile - It works on template. Its like adding a class element in to the DOM.
Link - It works on instances.
The concept of compile and link comes from C, where we first compile the code and then link it to actually execute it. The process is very much same in Angular as well.
In Angular not every directive will be able to demonstrate it, but "repeate" directive shows the difference very clearly.
To understand the difference lets try to debug the above code. Attach the debugger at line 2, 16 and 20. Here is the screent shot what i see when i am at line 2 -
->
The code looks very much similar to the one i have written in my HTML, no difference yet.Lets see what happens at line 16 -
We actually compiled the repeat tag and repeater compile function knows it has to create bunch of copies, hence it keeps the original syntax in comment and then internally compile the template itself.
Lets move to line 20 -
linking function creates the view.Once linking function is executes it creates the view, but it wont change the DOM itself, Once we call apply() function of angular, it renders the view for you.