The Mechanics of DOM Updates in Angular

The Mechanics of DOM Updates in Angular

DOM updates is part of Angular’s change detection mechanism. This article explores how the rendering part of change detection works and introduces the UpdateRenderer function. DOM updates that are triggered by the model change is the key feature of all modern front-end frameworks and the Angular is no exception.

DOM updates is part of Angular’s change detection mechanism. This article explores how the rendering part of change detection works and introduces the UpdateRenderer function.

DOM updates that are triggered by the model change is the key feature of all modern front-end frameworks and the Angular is no exception. We just specify the expression like this:

<span>Hello {{name}}</span><>

or a binding like this:

 <>

and Angular magically updates the DOM whenever the name property changes. It’s seems so easy on the outside but it’s actually a pretty complicated process on the inside. DOM updates is part of Angular’s change detection mechanism which mostly consists of three major operations:

  • DOM updates
  • child components Input bindings updates
  • query list updates

This article explores how the rendering part of change detection works. If you ever wondered how that is accomplished read on and achieve enlightenment. When referencing sources I assume that the application is running in production mode. Let’s start.

Application internal representation

Before we can begin exploring angular DOM updating functionality we need to first understand how Angular application is represented under the hood. Let’s briefly review that.

View

As you may know from my other articles for each component that is used in the application Angular compiler generates a factory. When Angular creates a component from a factory, for example, like this:

const factory = r.resolveComponentFactory(AComponent);
factory.create(injector);<>

Angular uses this factory to instantiate View Definition which in turn is used to create component View. Under the hood Angular represents an application as a tree of views. There is only one instance of a view definition per component type which acts as a template for all views. But for each component instance Angular creates a separate view.

Factory

A component factory mostly consists of the view nodes generated by the compiler as a result of template parsing. Suppose you define a component’s template like this:

<span>I am {{name}}</span><>

Using this data the compiler generates the following component factory:

function View_AComponent_0(l) {
    return jit_viewDef1(0,
        [
          jit_elementDef2(0,null,null,1,'span',...),
          jit_textDef3(null,['I am ',...])
        ], 
        null,
        function(_ck,_v) {
            var _co = _v.component;
            var currVal_0 = _co.name;
            _ck(_v,1,0,currVal_0);<>

It describes the structure of a component view and is used when instantiating the component. The jit_viewDef1 is the reference to the viewDef function that creates a view definition.

View definition receives view definition nodes as parameters which resemble the structure of the html but also contain many angular specific details. In the example above the first node jit_elementDef2 is element definition and the second jit_textDef3 is a text definition. Angular compiler generates many different node definitions and the type associated with the node is set in the NodeFlags. We will see later how Angular uses the information about the node type to decide how to handle the update.

For the purposes of this article we are only interested in element and text nodes:

export const enum NodeFlags {
    TypeElement = 1 << 0, 
    TypeText = 1 << 1<>

Let’s review them briefly.

Element definition

Element definition is a node that Angular generates for every html element. This kind of element is also generated for components. Element nodes can contain other element nodes and text definition nodes as children which is reflected in the childCount property.

All element definitions are generated by the elementDef function so jit_elementDef2 used in the factory references this function. The element definition takes some generic parameters:

+------------------+-----------------------------------+
|       Name       |            Description            |
+------------------+-----------------------------------+
| childCount       | specifies how many children       |
|                  | the current element have          |
| namespaceAndName | the name of the html element      |
| fixedAttrs       | attributes defined on the element |
+------------------+-----------------------------------+<>

And others that are specific to the particular Angular functionality:

+----------------------+------------------------------------------+
|         Name         |                Description               |
+----------------------+------------------------------------------+
| matchedQueriesDsl    | used when querying child nodes           |
| ngContentIndex       | used for node projection                 |
| bindings             | used for dom and bound properties update |
| outputs, handleEvent | used for event propagation               |
+----------------------+------------------------------------------+<>

For the purposes of this article we’re only interested in the bindings parameters.

Text definition

Text definition is a node definition that Angular compiler generates for every text node. Usually these are the child nodes of the element definition nodes as is the case in our example. This is a very simple node definition that is generated by the textDef function. It receives parsed expressions in the form of constants as a second parameter. For example, the following text:

<h1>Hello {{name}} and another {{prop}}</h1><>

will be parsed as an array:

["Hello ", " and another ", ""]<>

which is then used to generate correct bindings:

{
  text: 'Hello',
  bindings: [
    {
      name: 'name',
      suffix: ' and another '
    },
    {
      name: 'prop',
      suffix: ''
    }
  ]
}<>

and evaluated like this during dirty checking:

text
+ context[bindings[0][property]] + context[bindings[0][suffix]]
+ context[bindings[1][property]] + context[bindings[1][suffix]]

angular javascript web-development programming developer

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

Wondering how to upgrade your skills in the pandemic? Here's a simple way you can do it.

Corona Virus Pandemic has brought the world to a standstill. Countries are on a major lockdown. Schools, colleges, theatres, gym, clubs, and all other public

Why Web Development is Important for your Business

With the rapid development in technology, the old ways to do business have changed completely. A lot more advanced and developed ways are ...

JavaScript Roadmap in 2020 | How To Become A JavaScript Developer

JavaScript Roadmap will provide you with a detailed roadmap to begin your career as a JavaScript Developer in 2020.

Important Reasons to Hire a Professional Web Development Company

    You name the business and I will tell you how web development can help you promote your business. If it is a startup or you seeking some...

How to become a Web Developer | Web Development Career in 2020

How to Become a Web Developer will provide you with detailed roadmap to begin your career as a Web Developer in 2020.