Renderer2 In Angular

Renderer2 In Angular

The Renderer2 allows us to manipulate DOM elements without having to directly access the DOM. It creates a barrier between the DOM element and the code of the component. We can construct an element with Renderer2, add a text node to it, append a child element with the append child method, and so on. We can also change the styles, HTML attributes, CSS classes and properties, and so on. We can also attach events and listen to them.

Why not ElementRef?

To manipulate the DOM, we can use ElelemtRef's nativeElement attribute. This is what we learned in our last ElementRef article. The underlying DOM object is referenced by the nativeElement Property. This bypasses Angular and allows us direct access to the DOM. Although there is no harm in taking it, it is not recommended for the following reasons.

  1. Angular uses Templates, data binding, and change detection to keep the Component and the view in sync. When we update the DOM directly, we skip all of them.
  2. Only the browser supports DOM manipulation. You will not be able to use the App on other platforms where there is no browser, such as a web worker, a server (Server-side rendering), a desktop, or a mobile app.
  3. The data is not sanitized by the DOM APIs. As a result, we can inject a script, making our app an easy target for an XSS injection attack.

Using Renderer2

To begin, import it from the @angular/core folder.

import {Component, Renderer2, ElementRef, ViewChild, AfterViewInit } from '@angular/core';

injecting it into the part

constructor(private renderer:Renderer2) {
}

To gain a reference to the DOM element you want to change, use ElementRef and ViewChild.

@ViewChild('hello', { static: false }) divHello: ElementRef;

To update the property and styles of the element, use methods like setProperty, setStyle, and so on, as illustrated below.

this.renderer.setProperty(this.divHello.nativeElement,'innerHTML',"Hello Angular")
 
this.renderer.setStyle(this.divHello.nativeElement, 'color', 'red');

Setting & Removing Styles (setStyle & removeStyle)

To add or remove styles, use the setStyle and RemoveStyle commands. It accepts four different arguments.

The element to which we wish to apply the style is the first argument. The second argument is the name of the styles. The final point is the worth of the style. Flags for stylistic differences is the final argument.

abstract setStyle(el: any, style: string, value: any, flags?: RendererStyleFlags2): void
 
abstract removeStyle(el: any, style: string, flags?: RendererStyleFlags2): void

Example

//Template
 
<div #hello>Hello !</div>

//Component
@ViewChild('hello', { static: false }) divHello: ElementRef;
 
 
setStyle() {
  this.renderer.setStyle(this.divHello.nativeElement, 'color', 'blue');
}
 
 
removeStyle() {
  this.renderer.removeStyle(this.divHello.nativeElement, 'color');
}

Adding / Removing CSS Classes (addClass & removeClass)

To add or remove classes, use the addClass / removeClass methods.

Syntax
abstract addClass(el: any, name: string): void

abstract removeClass(el: any, name: string): void

Example
//Template
 
<div #hello>Hello !</div>


//Component
@ViewChild('hello', { static: false }) divHello: ElementRef;
 
addClass() {
  this.renderer.addClass(this.divHello.nativeElement, 'blackborder' );
}
 
removeClass() {
  this.renderer.removeClass(this.divHello.nativeElement, 'blackborder');
}

Setting or Remove Attributes (setAttribute & removeAttribute)

We can use the setAttribute and removeAttribute functions to add and remove attributes.

setAttribute(el: any, name: string, value: string, namespace?: string): void
 
removeAttribute(el: any, name: string, namespace?: string): void

Example
//Template
 
<h2>Add/ Remove Attributes </h2>
<input #inputElement type='text'>
<button (click)="addAttribute()">Set Attribute</button>
<button (click)="removeAttribute()">Remove Attribute</button>


//Component
 
@ViewChild('inputElement', { static: false }) inputElement: ElementRef;
 
 
addAttribute() {
  this.renderer.setAttribute(this.inputElement.nativeElement, 'value', 'name' );
}
 
 
removeAttribute() {
  this.renderer.removeAttribute(this.inputElement.nativeElement, 'value');
}

Setting Property (setProperty)

The setProperty method can be used to change any property of a DOM element.

setProperty(el: any, name: string, value: any): void

setProperty() {
  this.renderer.setProperty(this.divHello.nativeElement,'innerHTML',"Hello Angular")
}

AppendChild

To append a new element (child element) to an existing element, use the appendChild method (parent element).

appendChild(parent: any, newChild: any): void

There are two arguments that it accepts. The parent node, to which we want to attach a new child node, is the first argument. The child node that you want to add is the second argument.

The following two examples demonstrate how to use appendChild.

Insert Text Element (CreateText & appendChild)

We can use CreateText to add text to the DOM.

Example

A blank div (#divCreateText) appears in the following template.

//Template
 
<h2>Create Text Example</h2>
<div #divCreateText> </div>
<button (click)="createText()">Create Text</button>

Inject the reference to the divCreateText in the component using the ViewChild.

@ViewChild('divCreateText', { static: false }) divCreateText: ElementRef;

To make a text node, use the createText method. It is not included in the DOM at this time.

const text = this.renderer.createText('Example of Create Text');

To add it to an existing element, use the appendChild method (divCreateText).

this.renderer.appendChild(this.divCreateText.nativeElement, text);

Creating new Element (createElement & appendChild)

Using the createElement and appendChild functions, we can quickly create a new element.

createElement generates a new element but does not add it to the document object model (DOM). To insert it into the DOM, use the appendChild method to append it to an element that already exists in the DOM.

The following example demonstrates how to add a new element to the DOM.

In the constructor, we first inject ElementRef. This will inject the component/directive into the DOM element.

constructor(private el: ElementRef, 
            private renderer:Renderer2) {
}

Using the method createElement('div'), create a new div element. It hasn't been added to the DOM yet.

const div = this.renderer.createElement('div');

To make a new text node, use the createText('Inserted at bottom') method.

const text = this.renderer.createText('Inserted at bottom');

To append the freshly produced text node to the div element, use appendChild. It's worth noting that div hasn't yet been added to the DOM.

this.renderer.appendChild(div, text);

Finally, the div element is added to an existing DOM element, the host element.

this.renderer.appendChild(this.div.nativeElement, div);

The whole code can be found below. The createElement2 function adds a new div to the new child node.

Add the following code under the createElement.component.ts 

import { Component, Renderer2, OnInit, ElementRef, ViewChild, AfterViewInit, VERSION } from '@angular/core';
 
@Component({
  selector: 'app-create-element',
  templateUrl: './create-element.component.html',
  styleUrls: ['./create-element.component.css']
})
export class CreateElementComponent  {
 
 
  @ViewChild('div', { static: false }) div: ElementRef;
 
 
  constructor(private el: ElementRef, 
              private renderer:Renderer2) {
  }
 
  
  createElement() {
    const div = this.renderer.createElement('div');
    const text = this.renderer.createText('Inserted at bottom');
 
    this.renderer.appendChild(div, text);
    this.renderer.appendChild(this.el.nativeElement, div);
  }
 
 
  createElement2() {
    const div = this.renderer.createElement('div');
    const text = this.renderer.createText('Inserted inside div');
 
    this.renderer.appendChild(div, text);
    this.renderer.appendChild(this.div.nativeElement, div);
  }
 
}

Add the following code under the createElement.component.html:

<h2>Renderer2 Create Element</h2>
 
<div #div style="border: 1px solid black;">
    This is a div
</div>
 
<button (click)="createElement()">Create Element</button>
<button (click)="createElement2()">Create Element</button>

InsertBefore

Using the insertBefore method, we can also insert the new element before an element in the DOM element. The insertBefore syntax is illustrated below.

insertBefore(parent: any, newChild: any, refChild: any): void

the parent is the node's parent. The new node you wish to insert is newChild. The current child node before newChild is put is refChild.

The example below adds a new element before div1.

<h1>Angular Renderer2 InsertBefore Example</h1>
 
 
<div #div1>
  This is div 1
</div>
 
<div #div2>
  This is div 2
 
  <div #div3>
    This is div 3
  </div>
 
</div>
 
 
 
<button (click)="insertBeforeDiv1()" >Insert Before Div1</button>
 
<button (click)="insertBeforeDiv2()" >Insert Before Div2</button>
 
<button (click)="insertBeforeDiv3()" >Insert Before Div3</button>

To retrieve the reference to div1, first, use ViewChild. Then inject ElementRef, which provides us the reference to the Host DOM element.

Using createElement, create a new div element. Create a text node and attach it to the div using createText.

To add the div element, use the insertBefore technique.

import { Component, OnInit, ViewChild, ElementRef, Renderer2 } from '@angular/core';
 
@Component({
  selector: 'app-insert-before',
  templateUrl: './insert-before.component.html',
  styleUrls: ['./insert-before.component.css']
})
export class InsertBeforeComponent {
 
  @ViewChild('div1', { static: false }) div1: ElementRef;
  @ViewChild('div2', { static: false }) div2: ElementRef;
  @ViewChild('div3', { static: false }) div3: ElementRef;
 
 
  constructor(private renderer:Renderer2, private el:ElementRef) { }
 
 
 
  insertBeforeDiv1() {
    const div = this.renderer.createElement('div');
    const text = this.renderer.createText('This Text is Inserted before the div1');
    this.renderer.appendChild(div, text);
 
    this.renderer.insertBefore(this.el.nativeElement,div,this.div1.nativeElement);
  }
 
 
 
  insertBeforeDiv2() {
    const div = this.renderer.createElement('div');
    const text = this.renderer.createText('This Text is Inserted before the div2');
    this.renderer.appendChild(div, text);
 
    this.renderer.insertBefore(this.el.nativeElement,div,this.div2.nativeElement);
  }
 
 
 
 
  insertBeforeDiv3() {
    const div = this.renderer.createElement('div');
    const text = this.renderer.createText('This Text is Inserted before the div3');
    this.renderer.appendChild(div, text);
 
    //Using parentNode to retrieve the Parent Node
    this.renderer.insertBefore( this.renderer.parentNode(this.div3.nativeElement),div,this.div3.nativeElement);
  }
 
 
}

Insert Comment

createComment is a function that creates a comment node. It accepts an argument in the form of a remark. You can then place it anywhere in the DOM using the appendChild or insertBefore methods.

createComment(value: string): any

ParentNode & NextSibling

The ParentNode method in the host element's DOM returns the parent of a given node.

//Returns the parent Node of div3
this.renderer.parentNode(this.div3.nativeElement);

The nextSibling method in the host element's DOM returns the next sibling node of a given node.

//Returns the next Sibling node of div2
this.renderer.nextSibling(this.div2.nativeElement);

SelectRootElement

The selectRoomElement can also be used to select a node element based on a selector.

Syntax
selectRootElement(selectorOrNode: any, preserveContent?: boolean)

The selection or node is the first argument. The Renderer2 searches for and returns the DOM element using the selector.

preserveContent is the second parameter. Renderer2 will remove all child nodes if no or undefined. If the answer is yes, the child nodes will not be removed.

Consider the following template as an example.

<h1>Renderer2 selectRootElement Example</h1>
 
<div class="outerDiv" style="border: 1px solid black; padding :5px;"> 
 
  <div class="div1" style="border: 1px solid black; margin :5px;">This is Div1</div>
  <div class="div2" style="border: 1px solid black; margin :5px;">This is Div2</div>
  <div class="div3" class="div3class" style="border: 1px solid black; margin :5px;">This is Div3</div>
 
</div>

In the following example, selectRootElement returns the element div1, but it eliminates all of the content it contains. Due to the fact that the second argument is untrue. If you change false to true, the renderer2 will keep the content.

exampleDiv1() {
   const e = this.renderer.selectRootElement('.div1',false);    
}

Examples
exampleDiv2() {
  //Conent is always replaced. becuase preserveContent is false
  const e = this.renderer.selectRootElement('.div2',false);    
  const t = this.renderer.createText('Content added to div2');
  this.renderer.appendChild(e, t);

}

exampleDiv3() {
  //Conent is always appended. becuase preserveContent is true
  const e = this.renderer.selectRootElement('.div3',true);    
  const t = this.renderer.createText('Content added to div3');
  this.renderer.appendChild(e, t);
}

Listen to DOM events

The listen method can be used to listen to DOM events.

Three arguments are accepted by the listen method. The DOM element is the first argument (target). The event's name (eventName) is the second argument, and the callback is the third.

abstract listen(target: any, eventName: string, callback: (event: any) => boolean | void): () => void

In the example below, we listen for a button's click event.

//Component
 
import { Component, OnInit, ViewChild, ElementRef, Renderer2, AfterViewInit } from '@angular/core';
 
@Component({
  selector: 'app-listen-events',
  templateUrl: './listen-events.component.html',
  styleUrls: ['./listen-events.component.css']
})
export class ListenEventsComponent implements AfterViewInit {
 
  @ViewChild('hello', { static: false }) divHello: ElementRef;
 
  Count=0
  clicklistener;
 
  constructor(private renderer:Renderer2) { }
 
  ngAfterViewInit() {
 
    this.clicklistener = this.renderer.listen(this.divHello.nativeElement, 'click', (evt) => {
     this.Count++;
    });
 
  }
 
  ngOnDestroy() {
    this.clicklistener.unsubscribe()
  }
 
}

Please remember to unsubscribe from this clicklistener.unsubscribe().

//Template
 
<h1>Renderer2 Listen Events Example</h1>
 
 
<button #hello>hello</button>
 
Click Count {{Count}}

Conclusion

In this article, we learned what is Renderer2 in Angular and how to use it.

I hope this article helps you and you will like it.👍

If you have any doubt or confusion then free to ask in the comment section.

Post a Comment

Previous Post Next Post