Manipular el DOM en Angular: Renderer2
En ciertos momentos de nuestro desarrollo es necesario manipular el DOM de algún elemento, ya sea agregar alguna clase, estilo u otro elemento más. La lógica de personas que están acostumbradas a realizar desarrollos web, las lleva a utilizar JavaScript (o peor JQUERY), pero ciertamente esto está muy mal, ya que nos privamos de numerosas e importantes ventajas, como es el caso de la abstracción del DOM y la ejecución en entornos que no soporten DOM (como web Workers, aplicaciones mobiles y de escritorio). Además genera un acoplamiento indeseado entre la capa de renderizado y nuestra lógica, por ello Angular lo etiqueta como una mala práctica.
¿Cómo se manipula el DOM con Angular?
Para poder manipularlo, Angular provee de acceso a una clase denominada Renderer2,que nos proporciona una API para acceder de forma segura a elementos nativos, incluso cuando no están soportados por la plataforma (web workers, server-side rendering, etc).
Para poder empezar a utilizar esta clase, en nuestro proyecto, debemos inyectarla en el constructor y referenciar al elemento que deseamos modificar con ElementRef , que debe ir acompañado del decorador @ViewChild
import { Component, OnInit, ViewChild, ElementRef, Renderer2} from '@angular/core';
@Component({
selector: 'app-my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.css']
})
export class MyComponent implements OnInit {
@ViewChild("element") element: ElementRef; //REFERENCIAMOS AL ELEMENTO QUE QUEREMOS MODIFICAR
constructor(private renderer: Renderer2) { } //INYECTAMOS LA CLASE RENDERER
ngOnInit() {
}
}
Referenciamos con '#' el elemento deseado que queremos modificar.
<div #element>
<!-- OTRAS COSAS DENTRO DE NUESTRO ELEMENTO -->
</div>
Ahora lo que debemos hacer, es empezar a utilizar los métodos de Renderer2. Podemos añadir una clase, por ejemplo, con el método addClass.
Vamos a hacer que cada vez que hagamos click en nuestros elementos, que tengan la referencia #element, se nos añada la clase que queramos.
<div #element (click)="addClass()">
<!-- OTRAS COSAS DENTRO DE NUESTRO ELEMENTO -->
</div>
import { Component, OnInit, ViewChild, ElementRef, Renderer2} from '@angular/core';
@Component({
selector: 'app-my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.css']
})
export class MyComponent implements OnInit {
@ViewChild("element") element: ElementRef;
constructor(private renderer: Renderer2) { }
ngOnInit() {}
public addClass()
{
this.renderer.addClass(this.element.nativeElement, "claseNueva"); //El this.element.nativeElement hace referencia al ElementRef que declaramos anteriormente y a su referencia que utiliza el #element
}
}
Con esto ya podemos añadir cualquier clase sin tener que manipular el DOM de manera externa a Angular.
Como existe el método addCLass, también hay otros: removeClass, setAttribute, removeAttribute, etc. Con el poder de esta clase, podemos desde añadir o remover atributos hasta generar elementos nuevos en el DOM.
Conclusión
Como ven la clase Renderer2 es muy poderosa, y nos provee las suficientes cosas como para no tener que utilizar nada fuera de Angular. Próximamente, voy a crear una entrada sobre el uso de directivas para agregar y eliminar elementos del DOM dinámicamente y utilizaremos esto aprendido.
Enlaces de utilidad:
http://blog.enriqueoriol.com/2017/08/angular-dom-renderer.html
https://medium.com/@kmathy/angular-manipulate-properly-the-dom-with-renderer-16a756508cba