Manipula elementos del DOM con Angular 🅰 correctamente 👌 (Renderer2)

Publicado el 27.08.2022 a las 19:42

Manipula elementos del DOM con Angular 🅰 correctamente 👌 (Renderer2)

⚫ Ejemplo de lo que aprenderás

⚫ Así se resolvería con Vanilla JavaScript

🟣 HTML

🟣 TS

⚫ ¿Por qué debo evitar los métodos de document?

⚫ Como recomienda el equipo de Angular (Renderer2) 🧷

🟣 Cambiando la altura relativa de un elemento

🟣 Precaución 🚩

Manipula elementos del DOM con Angular 🅰 correctamente 👌 (Renderer2)

Ejemplo de lo que aprenderás

El botón es de color negro

Así se resolvería con Vanilla JavaScript

Para resolverlo con JavaScript obtendríamos el elemento del DOM con uno de los métodos que ofrece el objeto global document como por ejemplo getElementById('id del elemento').

HTML

<button (click)="changeColor()" id="myButton">
  <mat-icon>palette</mat-icon> Cambia de color
</button>      
<p id="myText">El botón es de color negro</p>
  

TS

  public changeColor() {
    const buttonElement: HTMLElement = document.getElementById('myButton');
    const textElement: HTMLElement = document.getElementById('myText');
    const currentColor = buttonElement.style.backgroundColor;
    if (currentColor === 'yellow') {
      buttonElement.style.backgroundColor = 'black';
      buttonElement.style.color = 'white';
      textElement.textContent = 'El botón es de color negro';
    } else {
      buttonElement.style.backgroundColor = 'yellow';
      buttonElement.style.color = 'black';
      textElement.textContent = 'El botón es de color amarillo';
    }
  }
  

¿Por qué debo evitar los métodos de document?

Usar los métodos facilitados por el objeto global document no es lo recomendable para manipular los elementos del DOM si estás usando Angular porque:

  • Angular mantiene el Componente y la vista sincronizados usando plantillas, vinculación de datos y detección de cambios, etc. Todos ellos se omiten cuando actualizamos el DOM directamente
  • La manipulación de DOM solo funciona en el navegador. No podrá usar la aplicación en otras plataformas, como en un service worker, en un servidor (SSR con Angular Universal por ejemplo), en un escritorio, en la aplicación móvil, etc., donde no hay un navegador.
  • Las API DOM no desinfectan los datos. Por lo tanto, es posible inyectar un script, lo que abre nuestra aplicación como un blanco fácil para el ataque de inyección XSS.

Como recomienda el equipo de Angular

El equipo de Angular recomienda manipular los objetos del DOM con la clase Renderer2👈

Te cuento:

  1. Asignaremos un alias a cada elemento del HTML al que querramos acceder desde el componente de TypeScript con el símbolo de numeral o hash (#) delante del alias

    <button
      color="primary"
      mat-raised-button
      (click)="changeColor()"
      #myButton
    >
      <mat-icon>palette</mat-icon> Cambia de color
    </button>
    <p #myText>El botón es de color negro</p>
      
  2. Con el decorador ViewChild cargamos el elementos del DOM con el alias especificado y le asignamos el tipo ElementRef:

    ViewChild se referencia desde @angular/core

      @ViewChild('myButton')myButtonInTS!:ElementRef;
      @ViewChild('myText')myTextInTS!:ElementRef;
      
  3. Inyectamos en nuestro contructor el Renderer2

    constructor(private renderer2:Renderer2)
  4. En la función que cambia el color hacemos uso del Renderer2 usando el método setStyle para cambiar los estilos del botón y usamos el método setProperty para modificar el texto del párrafo.

      public changeColor() {
        const myButton=this.myButtonInTS.nativeElement;
        const myText=this.myTextInTS.nativeElement; 
        
        if (this.isBlack) {
          this.renderer2.setStyle(myButton, 'backgroundColor', 'yellow');
          this.renderer2.setStyle(myButton, 'color', 'black');      
          this.renderer2.setProperty(myText, 'innerHTML', "El botón es de color amarillo"); 
        } else {
          this.renderer2.setStyle(myButton, 'backgroundColor', 'black');
          this.renderer2.setStyle(myButton, 'color', 'white');
          this.renderer2.setProperty(myText, 'innerHTML', "El botón es de color negro"); 
        }
        this.isBlack=!this.isBlack;
      }
      

Cambiando la altura relativa de un elemento

@ViewChild('myDiv')myDivInTS!:ElementRef;
private initialHeight:number;  

constructor(private renderer2:Renderer2){}

ngAfterViewInit(){
  this.initialHeight=this.myDivInTS.nativeElement.offsetHeight;
}

changeHeight(){
  const _myDiv=this.myDivInTS.nativeElement;   
  
  //aumento en 40px la altura inicial del div
  this.renderer2.setStyle(_screen, 'height', String(this.initialHeight+40)+'px');
}          
        

Precaución

🚩 Ten en cuenta que la asignación de la relación entre el html y el ts se hace justo antes del ngAfterViewInit, así que no puedes hacer uso de los elementos view child ni en el constructor ni en el ngOnInit.


Hasta luego 🖖

Servicios

Software

IoT

Digitalización

Aplicaciones móviles

Consultoría

fjmduran.com v0.2.2