What is Angular ElementRef ?

Angular provides a different way to manipulate the DOM element. The angular ElementRef class is one way to directly access the DOM for manipulation. Angular official documentation on ElementRef is a wrapper around a native element inside of a View. In javascript, we use get element by id to access DOM element, but we can’t use angular get element by id, this can be achieved using viewChild() decorator in Angular.

In this tutorial we’ll explore on angular elementRef on detials with two example of angular elementRef on component and directive. What are risk of using elementRef and we’ll explore other options of accessing DOM elements.

What is angular ElementRef. ?

In Angular applications, we can get direct access to any DOM element by using a special class called ElementRef. The angular elementRef gives direct access to DOM manipulation. We can use it inside a component or in the custom directive.

Example of how to use angular elementRef in component ?

When working with the Angular component, we often use @ViewChild decorator and template reference to get access to a specific element instance in a component typescript. Lets first create our angular project for elementRef example. Below angular cli command to create a project.

ng new elementRefExample
angular elementRef example
Angular elementRef example

In above is a screenshot of our elementRef example. An example below we have access paragraphs in DOM using @ViewChild decorator and define @ViewChild instance of type elementRef. In ngAfterViewInit() method we have added text inside a paragraph instance in component typescript. In our component template, we have hashtag # with the name paragraphRef as a local reference to the paragraph. Angular viewChild allows us to access our local reference variable of type elementRef class.

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

@Component({
  selector: 'app-root',
  // templateUrl: './app.component.html',
  template: `
  <h4>Angular ElementRef example </h4>
  <p #paragraphRef></p>
  `,
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements AfterViewInit {
  @ViewChild('paragraphRef') paragraphRef: ElementRef;

  ngAfterViewInit() {
    this.paragraphRef.nativeElement.innerHTML = 'Add text and manipulate DOM of paragraph';
    this.paragraphRef.nativeElement.classList.add("pstyle", "text-red");
  }
}

In a regular JavaScript application, we used document.querySelector() to get a reference to the DOM element. But in angular, we have @ViewChild() decorator to get a reference to an element from a component template. The ElementRef class defines a single property called nativeElement.

Note: We need to add our manipulation in ngAfterViewInit method is called as soon as the component view is created, so you are sure that the element you are waiting for is indeed present. If you try to do access in the constructor and ngOnInit, it won’t work. We need to wait for Angular to initialize the View, before accessing the ViewChild variables.

The nativeElement returns object which is used by the browser to represent the element in the Domain Object Model. This object provides access to the methods and properties that manipulate the element and its contents, including the classList property. We can use classList to add a list of CSS classes to the element. In our example, we have added two classes pstyle and text-red class and now we can add CSS to this class to add style to our elements. Let edit app.component.scss file.

.pstyle {
    background-color: rgb(230, 217, 217);
    padding-top: 20px;
    padding-left: 10px;
    height: 50px;
    font-weight: bolder;
}

.text-red {
    color: rgb(9, 96, 196);
}

How to use angular elementRef on a directive. ?

Creating an angular directive allows us to reused this directive in different components. Now we’ll demonstrate an example of how to used elementRef in our custom directive. We have already covered how to create custom directives in angular. For custom directive, the directive needs to access its host element for manipulation. The ElementRef which we will inject in the directive construct will give direct access to the host component/element in DOM for manipulation. An example here when hovering the mouse over a paragraph we are changing its font color. Here is the screenshot of when of both with and without hover of the paragraph.

Angular ElementRef example

Now lets generate directive called hoverer in our project and run following command to create our custom directive.

ng generate directive directives/hoverer

Now let edit our custom directive hover and add following code.

import { Directive, ElementRef } from '@angular/core';

@Directive({
  selector: '[appHoverer]',
  host: {
    '(mouseenter)': 'onMouseHover()',
    '(mouseleave)': 'onMouseLeave()'
  }
})
export class HovererDirective {

  constructor(private element: ElementRef) { }

  onMouseHover() {
    this.element.nativeElement.style.color = 'blue';
  }
  onMouseLeave() {
    this.element.nativeElement.style.color = 'black';
  }
}

In our custom directive, we have two function
1. onMouseHover method is called when the mouse hovers on our paragraph element. Based on hover we change the paragraph font color to blue and you can change any style based on your requirement.
2. onMouseLeave method is called when the mouse moves away from our paragraph element and based on the event we apply black to our font.

In our app.component.html file add the following code and we have applied our custom directive selector name in our paragraph. This is an element to which we want to apply a style using elementRef.

  <h4>ElementRef example </h4>
  <p appHoverer>Hover here to mouse to change font color.</p>

Why and when not to use angular elementRef. ?

The ElementRef object gives us direct access to the DOM element. It is not recommended not to use elementRef to modify DOM and it makes your application more vulnerable to XSS attacks. Use elementRef API for the last option when you need to access DOM directly. If we used ElementRef class only to get DOM element information, like an example of getting a certain width of DOM element, there is no security risk involved at all and we can use it.

There is a risk that can involve when you try to modify the DOM element using an ElementRef. In our previous example of elementRef on component, hacker may execute some code as below.

...
export class AppComponent implements AfterViewInit {
  @ViewChild('paragraphRef') paragraphRef: ElementRef;

  ngAfterViewInit() {
    // this.paragraphRef.nativeElement.innerHTML = 'Add text and manipulate DOM of paragraph';
      this.paragraphRef.nativeElement.onclick = SomeXsscodeFromUser;
  }
}

Relying on direct DOM access creates tight coupling between your application and rendering layers which will make it impossible to separate the two and deploy your application into a web worker.

From official angular doc on use of elementRef

How to prevent XSS attack on ElementRef

The best way to prevent XSS attacks is to prevent untrusted data (malicious code) from getting injected into the DOM tree. Angular have DomSanitizer class, which helps to prevent Cross-Site Scripting Security bugs (XSS) by sanitizing values to be safe to use in the different DOM contexts. Angular DOMSanitizer class has lots of methods that we can use and we used only one method for our example. So we have used and applied DomSanitizer class on our previous elementRef on angular directives.

import { Directive, ElementRef } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';

@Directive({
  selector: '[appHoverer]',
  host: {
    '(mouseenter)': 'onMouseHover()',
    '(mouseleave)': 'onMouseLeave()'
  }
})
export class HovererDirective {

  constructor(private element: ElementRef, private sanitizer: DomSanitizer) { }

  onMouseHover() {
    this.sanitizer.bypassSecurityTrustHtml(this.element.nativeElement.style.color = 'blue');
  }
  onMouseLeave() {
    this.sanitizer.bypassSecurityTrustHtml(this.element.nativeElement.style.color = 'black');
  }
}

When to used bypassSecurityTrustHtml method of DOMSanitizer.

Bypass security and trust the given value to be safe HTML. Only use this when the bound HTML is unsafe (e.g. contains tags) and the code should be executed. The sanitizer will leave safe HTML intact, so in most situations, this method should not be used

From angular official document on DOMSanitizer class

Alternative option of Angular elementRef. ?

We can use templating and data-binding provided by Angular instead of elementRef. Renderer2 is mainly used when creating custom directives. Unlike native javascript methods and Renderer2 class is an abstraction provided by Angular in the form of a service that allows manipulating elements of your app without having to touch the DOM directly. This makes it easier to develop applications that can be rendered in environments that don’t have DOM access, like on the server, in a web worker, or on native mobile.

We had articles on angular renderer2 and check articles on renderer 2 with an example. The renderer2 allows us to provides an abstraction for manipulating UI rendering elements of application at runtime without the need to access the DOM directly. This is the best approach to consider because of some security reasons like XSS Attacks.

Conclusion
In this article, we have explored details on Angular elementRef class uses and demonstrated two examples of angular ElementRef. There is no risk involved in getting DOM element information using elementRef, but the risk involved in modifying DOM element using elementRef. We can use angular DomSanitizer to prevent XSS attacks. Angular provides other alternative options to access the DOM element. I hope that this article was able to give you an idea of elementRef uses, disadvantages, and alternative ways of accessing DOM.

Related Post

Spread the love

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top