Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding step wise manual bootstrapping of angularJS

I was going through the basics of angularJS about how it is manually bootstrapped. I came across different approach and found this approach to be best fitted.

angular.element(document).ready(function(){
   angular.bootstrap(document,['myapp'])
})

Moving further, I came across this another way which breaks it to basics. I have commented the code as per my understanding but can someone please explain to me in more details about how things are working under the hood.

window.onload = function (){

  var $rootElement = angular.element(window.document);
  var modules = [
    'ng',       // angular module
    'myApp',    // custom module
    // what are we trying to achieve here?
    function($provide){ 
        $provide.value('$rootElement',$rootElement)
    }
  ];

  var $injector = angular.injector(modules);      // one injector per application
  var $compile = $injector.get('$compile');       // Compile Service: it traverses the DOM and look for directives and  compile and return linking function. No accecess to scope
  var compositeLinkFn = $compile($rootElement);   // collection of all linking function. Here scope is getting accessed

  var $rootScope = $injector.get('$rootScope');   // Hold of the rootscope
  compositeLinkFn($rootScope);

  $rootScope.$apply();
}

Also, please feel free to enlighten me more on this topic by suggesting more ways and improvements.

like image 201
Shashank Vivek Avatar asked May 20 '16 10:05

Shashank Vivek


1 Answers

what are we trying to achieve here?

var modules = [
    'ng',       // angular module
    'myApp',    // custom module
    function($provide){ 
        $provide.value('$rootElement',$rootElement)
    }
  ];

That is same old dependency injection we use everywhere in angularjs. Here we are injecting the module ng and registering a value into it.

And finally we are passing it in angular.injector()

  var $injector = angular.injector(modules)

Still not convinced? Here's the simpler version(the way we use DI in controllers)

var $injector = angular.injector(['ng','myApp',function($provide){
    $provide.value('$rootElement',$rootElement)
}])

Now two questions,

  1. why are we using angular.injector ?

    Because, angular.injector creates an injector object that can be used for retrieving services as well as for dependency injection. We would need this to get $compile service and an instance of scope to bind that template with.

  2. why are we setting $rootElement ?

    To let angular know the root element of application. Noticed the use of document in angular.bootstrap(document,['myapp'])? It is for the same reason.

    According to the official documentation of $rootElement,

    $rootElement is either the element where ngApp was declared or the element passed into angular.bootstrap.

    Since we are neither using ng-app nor the standard angular.bootstrap method, we have to set this manually.

Next, we try to get $compile service from the instance of injector we just received from above step.

var $compile = $injector.get('$compile');

The $compile service is the service to use for compilation. Invoking $compile against a markup will produce a function you can use to bind the markup against a particular scope (what Angular calls a linking function)

Again to get the scope, we use $injector.get('$rootScope') and pass it on to composite link function we got from $compile.

angular.bootstrap(document,[myApp]) is just a syntactical sugar over above mentioned steps. It creates an injector instance, set relevant services with the help of it, creates application-wide scope and finally compiles the template.

This is evident from the official documentation for angular.bootstrap, which clearly mentions that it returns an injector instance.

auto.$injector Returns the newly created injector for this app

Same story is indicated in the official bootstrap guide

Note that we provided the name of our application module to be loaded into the injector as the second parameter of the angular.bootstrap function. Notice that angular.bootstrap will not create modules on the fly. You must create any custom modules before you pass them as a parameter.

Finally, needless to say..all this has to be done after HTML-Document is loaded and DOM is ready.

EDIT

Here's a diagrammatic representation of this process. angular.bootstrap process
(source: dotnet-tricks.com)

Image Reference

Hope it helps :)

like image 174
nalinc Avatar answered Oct 11 '22 06:10

nalinc