How angular js works

1 bootstrap flow:

  • angularInit method which checks for ng-app module
  • bootstrap method which is invoked once an ng-app module is found. Following are key invocations from within bootstrap method:
    • createInjector method which returns dependency injector. On dependency injector instance, invoke method is called.
      For example if myModule has ‘greeter’ dependency. we get it like this

      var injector = angular.injector(['myModule', 'ng']);
      var greeter = injector.get('greeter');

      the greeter is usually provided by some factory/service/provider

      myModule.factory('greeter', function($window) {
        return {
          greet: function(text) {
    • compile method which collects directives
    • Composite linking method which is returned from compile method. Scope object is passed to this composite linking method
    • $apply method invoked on scope object finally does the magic and renders the view.

Another article on how module bootstraps

2 $watch How the $apply Runs a $digest

$watch will be created for the needed dom element. It takes a watchFn(which is usually the scope variable name) to return its own latest value and a listnerFn for the change callback.

$digest will go into the angular context(watched elements) and run the digest loop which compares the changes(new value are return by all watches) until all the elements are up to date(up to 10 loops if infinite loop). We do not usually call digest directly but uses apply more unless there are some heavy filters used(look at the below difference link).

$apply will call digest from the rootscope and go thru all its children scopes. Most of the time(angular’s own directives) this is called automatically. When you use some third part library(jQuery) or update var of scope in your own directive(meaning the event is from DOM directly), you will need to call this explicitly to let the event go thru the angular context.The most important thing to keep in mind is whether or not Angular can detect your changes. If it cannot, then you must call $apply()manually. The better practise is to pass the needed changed as a function to the apply like:

scope.$apply(function(){scope.a = a; $parse(attrs.b).assign(scope, ‘b’);})

main different between digest and apply

3 detail on watch/digest

4 Injection(service/facotry/inject)

The DI is actually done rely on the fact that javascript could turn a function to String by calling .toString(). For example

var f = function(a, b, c){};

console.log(f); console.log(f.tostring());

This way, angularJs could get the arguments in String format and do analysis then corresponding injection.

Note the best practice to DI is to specify the name list first then put the objects into function so that even the js is minified, it would still work. Angular doc about this


admin.controller(‘BillingSchedulerController’, [‘$scope’, ‘$filter’, ‘JobControlResource’, ‘$timeout’, function ($scope, $filter, JobControlResource, $timeout)

the reason we can do this is, when angular saw the second param of controller is array instead of a function, it starts to parse the first n-1 elements of the array and inject into the n element which is a function. and then call the elementN() with corresponding dependencies. this is a good video explaining this point. 

A side note, angular.$injector().annotate(yourFunction) will get all the argument of ‘yourFunction’ as an array.

My other post briefly describes the difference between service/factory/provider. Basically they are all for DI so that the objects($scope, $filter, JobControlResource, $timeout) above could be injected.

5 directives

a detail video on how directive works from the author of angular

Basically compile function compiles the html template. link function applies the scope to the template.

New scope in directive

The scope:true is useful so that whatever we do in the directive does not pollute the outside world. it will be an isolated scope which is not inheriting!

1. We also could import the outside value by scope:{email : @}. use @ to use the {{email}} style. this way it is passing an email string in.

2. use scope:{email : ‘=’} to use a expression passed in. this way is passing a reference of an object in.

Scope properties come in three different flavours

  • Two-way binding: Indicates that changes made on either the parent or child scope are reflected in the other. It’s denoted by an equals sign (=) when building the scope.
    Use ‘attribute=parentField’ to pass the parentField object to the directive to achieve two way binding. see this example
  • One-way binding: Data flows only from child to parent via a function. Denoted by an ampersand (&).
    Use ‘attribute=parentFunction(someVal)’ to pass the parentFunction to the child so that it could be called there. in the directive, it could be called by scope.parentFunction({someVal:’someString’}). Here someString could also be a field in the scope so that it could be dynamic. see this example
  • Text binding. Just a string value that contains no binding information. Denoted by an at symbol (@).
    To pass value from the parent, use ‘attribute={{parentField}}’ so the parentField could be a dynamic value. see this example
  • review


the  transclude: true will pull the content of the ng-transclude out of the directive scope so that it could still received value from outside world. The inside content scope is a sibling scope with the directive scope. They are both child of the upper scope. The difference is the directive scope is not inheriting but the inside content scope inherits values from the parent.(this is explained from the above youtube video starts @45:00)


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s