Chathuraka Mallawa Aarachchi

Change detection in AngularJS and Angular

In this latest technical guide from Mitra Innovation, Chathuraka Mallawa Aarachchi writes about detecting changes relating to Angular and AngularJS, and how to analyse the state of change when the state of a Javascript code-based model undergoes change.

AJ logo
Understanding what a change is?

When a model state undergoes changes, it is very likely that related user interfaces too will experience changes. The changes available for user interfaces are typically passed from the model to the Document Object Model (DOM). The changes from the model are asynchronous and the DOM needs to be updated during the runtime of the browser without re-rendering. DOM rendering tends to be a resource expensive task on the browser. The ideal way to achieve this is by injecting identified model changes during run-time to the DOM.

Let’s take a look at how javascript handles this:

<div id=”demo”>DEMO</div>
<div id=”target”>Text</div>

var handleClick = function (event) {
document.getElementById(“target”).innerHTML = “Text changed”;
};
var element = document.getElementById(“demo”);
element.addEventListener(‘click’, handleClick);

(Code Snippet 1)

 

Here (above code snippet 1) we see a click-event-callback function bound to the div element with ‘demo’ as the ID. When this element is clicked, the model changes state, and then updates the content of the div element with ‘target’ as the ID. It is clear in the above example that the click-event logic can be handled through the ‘handleclick’ function.This event is bound in javascript logic for DOM elements with ID’s equal to ‘demo’. This is the conventional way of binding data that is used in Javascript, Jquery and similar frameworks such as Backbone. However, in the case of complex data binding scenarios, it can be quite a task to track all the changes required.

Angularjs change detection

When a task is actioned through the web page view, the model is requested to carry out an action to handle the business logic. This causes a change to the current state of the model. Ideally, whilst code updates are being executed, the DOM needs to be simultaneously updated to keep track of changes. Frontend frameworks such as AngularJS are capable of identifying changes to model states, and promptly updating all areas of the DOM where necessary.

Programming data that needs to be changed using ‘watcher’ functions and controlling the changes a user needs to see.

In AngularJS, all DOM data bindings are monitored by watchers. A ’Watcher’ is a function assigned to check the state of a model variable for a particular data binding. When a model state undergoes changes, the watcher function instructs to mark that particular variable to be passed onto the DOM as soon as AngularJS is ready to update the DOM elements.

Watch functions can also be listed for re-use later in AngularJS. Watchers are lined up in a list called a ‘watch list’ and can be used by AngularJS at a later stage – known as a ‘digest loop’ – which I will explain further, below.

Although AngularJS allows for unlimited number of watching functions, the recommended maximum number of watchers is at 2,000 per view. All watchers within a single view are processed using a processing technique known as a ‘digest cycle’. Watchers inside a digest cycle are subject to ‘dirty checks’.

A dirty check is a common design principle that is used to determine whether old values of variable have undergone changes. Such checks are carried out in each of the watcher functions that are included under the current scope. Following every model state change, the watch list is executed and dirty checks carried out to know the changes updated for viewing.

The following diagram illustrates how AngularJS processes a watchlist within a digest loop.

(Fig 2: Digest loop minimum number of cycles)

 

When the first digest cycle detects a change to a scope variable, the digest loop is required to execute once more in order to resolve changes to variables.

(Fig 2: The digest cycle executes one more time when a change is detected)

 

AngularJS, on its own, is not capable of identifying the exact scope variables that need to be updated following an event. As a result, AngularJS runs the digest loop and executes dirty checks on all of the watchers listed on the DOM within the selected scope. Should a value have undergone changes caused by event model logic, a dirty check will identify the change when it resolves the next digest cycle. When the digest cycle concludes its run, Angular hands over the changes within a Javascript context to update the DOM with new changes.

This method of running digest cycles to carry out dirty checks on all scope variables is not a very efficient way of updating changes. The ideal way is to check only for variables that will be affected by changes.

This is where we introduce Angular, also called Angular2

Angular change detection

When Angular detects a change in the model, only the precise areas are affected – without disturbing other data bindings within the DOM. The high level picture is as simple as: why should dirty checks be carried out on all data bindings if we know the exact ones that need to be checked?

This question might have been asked a thousand times by the Angular team before they arrived at Angular.

Once the state of a model has undergone asynchronous changes – the area of the DOM for that particular change might quite simply be a text change or a button change – on the model. This is a variable, array or object. These variables are known as components in Angular. Components have limited input parameters required to handle operations within a component.

However, if it is possible to identify and check component inputs as and when a change occurs, and instruct Angular not to open a component that has no changes relating to it; that would be the ideal way to drop a whole subtree for that change.

This way, Angular can focus precisely where is required, i.e. focus only on the bits that have undergone change.

There is a solution however. ‘Zone’ can overcome this challenge in Angular. With Zone, Angular can start checking changes from the parent compound to the lowest level of the tree.

(Fig 3: Angular model – view of communications)

 

Immutables in Angular

Other than for primitive data types, objects are mutable by default in Angular. When the properties of an object undergoes changes without the object reference undergoing changes; the object is considered as unchanged.

This means we are unable to reduce the number of checks if object references cannot be checked when subject to change detections.

Zone (ngZone in Angular) can help by making objects as immutable. When an immutable object undergoes changes, the object’s reference is also subject to changes. This way, change detection functions can easily be informed of change occurrence within the component.

(Fig 4: Skip subtrees using immutables)

 

Observables in Angular

Observables allow us to subscribe to a particular change when a particular variable undergoes changes. Immutable does not subscribe to events, it simply disables a subtree that has no relation to a change. Certain times, this may not be sufficient for certain components to perform their designated tasks. In such instances, changes are executed for that particular subtree only.

Conclusion

The change detection pattern of Angular is one of the main advantages Angular offers over AngularJS. It is also one of the main difficulties of the conversion from Angularjs to Angular. It is always good to know the core of the frameworks before trying to migrate the versions. This knowledge can help us when we deal with critical error scenarios as well.

Thank you for reading this Tech Guide. We hope you will also read our next tutorial so that we can help you solve some more interesting problems.

Chathuraka

Chathuraka Mallawa Aarachchi

Senior Software Engineer | Mitra Innovation