Monday, December 23, 2013

Data binding in AngularJS

One of the most important things in AngularJS is the data binding. In fact I think it is so important it should be one of the first things you should get to know if you start to write Angular apps. It should be explained more and it shouldn't be just "the magic that we won't cover right now".

The real magic behind Angular's data binding is called dirty checking. Basically every time you write {{myModel}} in the background a new watch for the expression myModel is being created that on every $digest cycle will be evaluated and if the value of the model is changed, the DOM will be updated. Thanks to this dirty checking we are also able to use plain old JS object as our model. How data binding works is explained in detail in this great article - http://angular-tips.com/blog/2013/08/watch-how-the-apply-runs-a-digest/. I also recommend to read Misko's answer to this StackOverflow question on why dirty checking is not a bad thing, unless of course it is used in a bad way. This is why we should understand how data binding works.

An example of such a bad use would be to bind to a function that makes some complex computations. In this example not so complex, but lets have have an input that will represent a value for radius of a circle and we will calculate it's area and show it. We can create a function and bind to it
However if you look at the console output, you will see that on every radius change, it is called twice, once on the first loop of the $digest cycle and because the area value was changed it will called once again in the second loop. We can even bind to this function in multiple places in the view, and unlike I expected it to work, for each one of them it will add a watch in the $watch list, and the function will be called multiple times. For example if we add
<div>Area {{calculateArea()}}</div>
on 3 places, then when the value of radius is changed, calculateArea() will be called 2*3=6 times. So if this was computing something more complex it would really be an issue.

 We can optimize this by listening the radius for change, compute the area based on the new radius value and assign the result to the scope. That way the computation will be done only once.
Of course if we include
<div>Area {{area}}</div>
 again the 3 watches will cause the evaluation of the area model value, but since it is assigned to the scope it will be much faster.

The book Mastering Web Application Development with AngularJS explains really well how data binding works, how the DOM and model are synchronized, what is scope.$apply, how $watches are registered and how the $digest cycle executes. It also has a nice step by step explanation of how the 2-way data binding is achieved in Angular. A must-read book!

No comments:

Post a Comment