While working as the front-end developer, the most important point to focus is to manipulate the DOM as less as possible which in turns may improve the web performance.
As we all know that Angular was developed to run on all platforms like browser, webworkers, universal, pwa.
In this article, we will emphasize on the following points.
1. Correct approach working with DOM.
2. Tools to work with DOM.
3. View and rendering layer architecture.
Any Angular application has rendering and presentational logic.
I know most of us know about it. Still, we will try to decipher the difference between them.
Suppose, we have two list of the data that needs to be rendered as the left and the right panel. On the left panel, we have menu items by category and based on the category, we display the items in the right panel.
The presentational logic goes to the component. The component is sort of the container with the view/ presentations specific data.
So, now the question is where to put the rendering logic.
So, there is layer between the component and the DOM element is the directives where we encapsulate the templates and perform the manipulation within the directives. Then, we pass the data binding to the directives and render the business related data to the UI.
So, just to recapitulate the points whatever we have learned so far.
1. Split the presentational and rendering logic.
2. Put the presentational logic to the components.
3. Put the rendering logic to the directives.
4. Use the data-binding mechanism for the communication.
So, using the above approach has 2 benefits overall.
1. Presentational logic can be reused on the other platforms.
2. Rendering logic reuse across the application.
Angular, by default, don’t provide the built-in directive to the above approach. So, we need to implement the custom directive for it which we will see it in action going forward.
Let’s try to use a custom directive inside a component.
Nothing, great at this point until we see how the custom directives is implemented.
So, if we see the above code, this is how the custom directive is implemented. But, if we look the code, we are directly accessing the api to manipulate the DOM which Angular doesn’t recommends.
The reason is the plaform dependence as we have discussed above.
The Non-DOM environments like Universal, Webworker. If we try to run the directive inside WebWorker, it will result in an error.
But, we have tools which makes the DOM access safe. Here comes the point, where will uncover the ways to manipulatet the DOM in Angular.
Before manipulating DOM, first we need to understand what operations are will going to perform on the DOM.
Generally we can categorize into two parts as shown in the below diagram.
In a nutshell, it as follows:
Renderer: Use when we need to change/read DOM element properties.
ViewContainerRef: Use when we need to modify DOM hierarchy.
We will try to see both these ways in much detail.
Renderer (Renderer 2): It marks the direct DOM access safe (platform independent).
Few DOM manipulation methods as follows:
If we look the implementation of the custom dirctive using Renderer2 in recommended Angular way.
So, if we think how Renderer service is making this code implementation, lets’ visualize the Renderer architecture how it makes possible.
The main piece in connecting the dot is the DOM adapter which acts as a bridge between the Native API( browser) / platform and the framework (Renderer). It’s implementation is always platform specific.
But, there is one more point to note that each component in Angular depends on how to render the view. We have used the encapsulation like Native, Emulated (default), ShadowDOM, None.
So, Renderer service depends on the component encapsulation before the DOM is manipulated.
In turn, the Angular create the dedicated Renderer as per the component.
So, this is the reason we can’t inject the Renderer in the standalone service.
Hope the above diagram makes sense the connection between the View Encapsulation and Renderer.
For the layer of bit comfortability, attaching a diagram to get idea different Renderer abstraction on different platforms.
Sidenote: Don’t use Renderer for the DOM hierarchy modification.
Moving ahead with the other piece of the DOM modification is the ViewContainerRef.
So, to understand the ViewContainerRef, we first need to understand the
relationship between the View and the DOM.
Lets’ visualize the diagram.
So, when we create a component in Angular, the compiler in turns takes the set of the template instructions from the component and creates the view. In turn, the view creates the node elements (depends on the template).
View is core-concept of Angular. It’s an abstraction which associates the DOM elements defined in the component templates.
Now, to our surprise, we define the component, but how the view gets created. The angular compiler does that. Let’s see this diagram.
If anyone have worked on the AOT compilation, we might have seen the viewfactory. But, what exactly is the ViewFactory?
ViewFactory can be interpreted as a set of instructions (what type of view and DOM nodes) getting from the component template and which in turns creates the view.
Basically, the instruction set has 1–1 relationship between the components and its view which gets resolved by the View Factory. We can take the example of the dynamic component creation in Angular.
One important to note that the Angular Change Detection works with the View. Any changes in the view reflec the changes in the DOM elements defined in the component. So, its a one way process.
Now, let’s remove the span element from the DOM. We will see that the structure of the DOM gets changed but the structure of the view is intact.
The answer is even if we have removed the element from the DOM, its’ reference is still present in the View which creates the possibility for the memory leak.
Imagine, we have a component with the lot of DOM elements and removing one element from the component tree still have its reference in the view nodes. So, when the angular change detection mechanism runs, it will still run on the removed element from the DOM which has it’s reference in the view. So, in order to access the DOM safely, we use the ViewContainerRef.
ViewContainerRef: Makes DOM hierarchy changes safe.
1. createComponent (dynamic component creation) — Created from the view factory. Component that is not found other component templates.
2. createEmbeddedView (TemplateRef) — In Angular, we reference template using the Template ref (a reference to the compiled template).
View manipulation methods
To conclude this article, just a few takeaway points.
- put presentational logic into components.
- use custom directives to manipulate the DOM to make it more platform independent and DOM safe.
- Use Renderer when direct access to native DOM api is necessary.
- Use templating technique and ViewContainers to modify the DOM hierarchy.
Hope, you have got some sense on how the work with the DOM manipulations in Angular.
Happy coding. Keep learning. Keep exploring. 😊