How databinding works in Angular JS?


Its a basic question that comes to most of the developers mind while learning angular js.  And its very obvious that it came to my mind too as I come from the same background.

So the first word I heard while trying to know about this is "dirty-checking".
Yes angular js uses dirty checking for data binding. Now what is Dirty checking?

Dirty Checking
This basically means that if the value gets dirty or changed from what it has maintained then  events associated gets executed. Angular js basically remembers the old value and compares with new one and get to know that whether the change event is to be executed or not. We call $apply() method in angular js which performs a $digest after evaluating the expression. In the $digest phase the scope examines all of the $watch expressions and compares them with the previous value. So digest basically is the cycle that does dirty checking.

Next question that arises is "What exactly is done when you call $digest to do dirty checking?"
As far as I know $digest evaluates watch expressions on all the variables monitored by all the $scopes and compares with the old value and fires listeners accordingly.   

$watch helps to listen for $scope changes

You can also create your own watches. Thus, $watch helps you to execute few lines of code when any variable attached to the $scope gets changed. It is rarely used, but sometimes is helpful.

Below is the syntax of watch expression.

$watch(watchExpression, [listener], [objectEquality]);

This registers a listener callback to be executed whenever the watchExpression changes.
For instance, if you want to run some code each time 'anyvar' changes, you could do the following:
 
function MyController($scope) {
   $scope.anyvar = 6;

   $scope.$watch('anyvar', function() {
   // this is listener method which will be call if it finds the changes
       alert('hey, anyvar has changed!');
   });

   $scope.buttonClicked = function() {
      $scope.anyvar = 4; // This will trigger $watch expression to kick in
   };
}

Here third parameter [objectEquality] allows us to force angular to compare two object by angular.equals method. By default it compares the references by using !== operator. angular.equals does a deep comparison and does not depend on the order of the keys.

var obj1 = {
  key1: "value1",
  key2: "value2",
  key3: {skey: "svalue", skey2: "svalue2"}
}

var obj2 = {
  key2: "value2",
  key1: "value1",
  key3: {skey2: "svalue2", skey: "svalue",}
}

angular.equals(obj1, obj2) // returns true



Data binding is always initiated via $.apply().

 Everything in Angular JS  where binding is done like user interaction with HTML input elements(input directive) , select element(select directive), etc all of these uses use scope.$apply() internally.
Similarly all the changes outside Angular JS world also use $rootScope.$apply() for data binding.

Another question that arises is "Why  and when should I invoke $apply if everything gets executed automatically"

Listeners gets executed only for those scope variable changes which lies inside the angular scope. This is because angular framework only know the changes which are done under its scope. There may be cases where we need to change the scope variables values outside the angular world or function out of angular scope.
A very simple case can be that you want to change the scope variables value($scope.anyvar) on success of an ajax call. So you need to figure out a way to intimate angular framework that the value of scope variable is changed and it need to invoke the associated change listeners. So here comes $apply in rescue to this problem.
With $apply you can enable communication with the angular world being outside of its scope. It internally starts the digestion cycle and also take cares of the errors and exception with proper exception handlers.

Here is an example:

$.ajax({
 url:"abc.do",
 type:"post",
 success: function() {
  scope.anyvar++;
  scope.$apply(); // This line will do the magic
 }
});

So in the above example scope.$apply() tells the angular framework about the changes that are done to the scope variable. But by this method angular will never come to know about the errors if they occur while data-binding. Here is a better way.

$.ajax({
 url:"abc.do",
 type:"post",
 success: function() {
  scope.$apply(function(){
   scope.anyvar++;
  });
 }
});

Now this wrap function will give full control to the angular framework. So the basic difference is that in the first version "If any error is thrown while updating the values, Angular will never come to know about this". But in the second version with wrap function, it gets informed about the error thrown. So if there is a need to show error message to the user, we can achieve it via this wrap function.

 So this is how the whole data-binding process works in angular js. I hope there are a lot of other question that might be arising in your mind while reading this article. Feel free to ask in comments. I will try my best to answer those if I am able to. Also I would love to know feedback from about this article.

Related

technology 1720316012269880852

Post a Comment

  1. For example purposes, this is great - but why are you using $.ajax rather than $http.post?

    ReplyDelete
  2. You are correct but as you can see that it was just to describe the use of $apply(). I could have given any other example too. Thanks for your feedback.

    ReplyDelete
  3. Very clear explanation. Looking forward to more posts on angular.

    ReplyDelete
  4. Nice Article. Keep Blogging

    ReplyDelete
  5. Kushagra Thapar8 March 2014 at 05:34

    Great illustration..!!
    Just a typo.. in example where you have mentioned angular - js does a deep comparison.. value of skey2 in obj2 is not equal to value of skey2 in obj1..:P

    ReplyDelete
  6. Thanks Kushargra for your valuable feedback!
    Btw, I have corrected the typo. :)

    ReplyDelete
  7. I'm new to angular so I'm just trying to understand this. I thought the reason that $scope variables trigger data-binding events automatically when they change was because they were attached to $scope, so they have 'watchers' on them already. So in your ajax example where you have to call $apply after changing a scope variable is confusing me. The variable is attached to the scope, so I would assume it would already trigger the data-binding events automatically when it changes, thus not needing $apply.

    ReplyDelete
  8. Nevermind, I looked it up. Your wording was a little confusing when you were explaining $apply being used internally by angular and changes only being detected when "in angular scope", I guess because when you say scope there you don't mean $scope. I realize now that any code executed within an angular construct like controllers or ng- directives, etc. is automatically wrapped in $apply for you, which is why those changes are detected automatically. But, when creating your own block of code outside of anything angular controls, you need to manually call $apply because it isn't wrapped for you.

    ReplyDelete
  9. Good one .

    I wrote about angular routing here

    http://angulartutorial.blogspot.in/2014/02/how-to-start-with-angular.html

    ReplyDelete

emo-but-icon

Translate

 

Recent Posts

comments

Recent Comments Widget

Join Us

 

Sponsored By

Recommended for you

get social

item