50 - Directivas de atributo - responder a eventos del usuario dentro de la directiva

Cuando creamos una directiva personalizada podemos capturar eventos dentro de la misma para reaccionar. Podemos por ejemplo detectar y reaccionar cuando el mouse entra o sale del elemento HTML que estamos aplicando la directiva.

Problema

Crear una directiva personalizada que se pueda asociar a cualquier elemento HTML y cuyo objetivo sea mediante la síntesis de voz hacer la lectura del contenido de texto que contiene la etiqueta. La lectura debe comenzar cuando el usuario dispone el mouse sobre la etiqueta y terminarla si saca la flecha del mouse.

  • Crearemos primero el proyecto

    ng new proyecto035
    
  • Procedemos a crear la directiva de atributo personalizada llamando a la misma 'textovoz' (indicamos que no queremos prefijo):

    ng generate directive textovoz --prefix
    

    Se crean dos archivos.

  • Procedemos a modificar el archivo 'textovoz.directive.ts' implementando la lógica de nuestra directiva:

    import { Directive, ElementRef, HostListener } from '@angular/core';
    
    @Directive({
      selector: '[textovoz]',
      standalone: true
    })
    export class TextovozDirective {
    
      constructor(private elemento: ElementRef) {
      }
    
      @HostListener('mouseenter') entradaMouse() {
        speechSynthesis.speak(new SpeechSynthesisUtterance(this.elemento.nativeElement.textContent));
      }
    
      @HostListener('mouseleave') salidaMouse() {
        speechSynthesis.cancel();
      }
    
    }
    

    Se inyecta al constructor un objeto de la clase 'ElementRef':

      constructor(private elemento: ElementRef) {
    

    Debemos importar 3 clases, que se almacenan en '@angular/core':

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

    Para captura de eventos debemos utilizar la función decoradora @HostListener pasando como parámetro el nombre del evento a capturar:

      @HostListener('mouseenter')
    

    Cuando el usuario ingresa la flecha del mouse dentro de la componente, mediante el objeto 'speechSynthesis' y la clase 'SpeechSynthesisUtterance' procede la alocución del string que le pasamos como parámetro, el mismo lo rescatamos del contenido de la etiqueta HTML:

      @HostListener('mouseenter') entradaMouse() {
        speechSynthesis.speak(new SpeechSynthesisUtterance(this.elemento.nativeElement.textContent));
      }
    

    También capturamos el evento 'mouseleave' donde procedemos a cancelar la alocución del mensaje, en el caso que no se haya terminado previamente:

      @HostListener('mouseleave') salidaMouse() {
        speechSynthesis.cancel();
      }
    
  • Para probar la directiva 'textovoz' vamos a utilizar la componente que Angular nos ha creado por defecto, modificamos el archivo 'app.component.ts':

    import { Component } from '@angular/core';
    import { CommonModule } from '@angular/common';
    import { RouterOutlet } from '@angular/router';
    import { TextovozDirective } from './textovoz.directive';
    
    @Component({
      selector: 'app-root',
      standalone: true,
      imports: [CommonModule, RouterOutlet, TextovozDirective],
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
      title = 'proyecto035';
    }
    

    Y el archivo 'app.component.html':

    <p>Como se pronuncia la palabra: <span textovoz>casa</span></p>
    <p>Como se pronuncia la palabra: <span textovoz>ventana</span></p>
    <p>Como se pronuncia la oración:</p>
    <pre textovoz>
        Aquí me pongo a cantar
        al compás de la vihuela
        que el hombre que lo desvela
        una pena extraordinaria
        como el ave solitaria
        con el cantar se consuela
      </pre>
    

    Como vemos simplemente agregamos la directiva de atributo que hemos creado:

    <span textovoz>casa</span>
    

    Podemos probar esta aplicación en la web aquí.