Skip to main content

Gestionar eventos en Componentes Web Lightning.

Objetivos de aprendizaje

Después de completar esta unidad, podrá:

  • Crear una aplicación que incluya múltiples componentes.
  • Describir la estructura de archivos de un componente complejo.
  • Gestionar eventos.

Seguir la trayectoria de un evento

Ya construyó un componente y lo envió a una organización. Empecemos ahora a agregar algunas interacciones con la gestión de eventos. Seguimos la trayectoria de un evento a través de varios componentes para gestionar un evento sofisticado en una aplicación. Esta aplicación es un selector de productos para una tienda de bicicletas. Los usuarios hacen clic en el nombre y la imagen de una imagen para ver los detalles.

Los componentes del selector de bicicletas.

En esta aplicación hay cuatro componentes:

  1. tile (mosaico): muestra un elemento individual.
  2. list (lista): ordena los mosaicos.
  3. detail (detalles): muestra detalles de los elementos cuando se hace clic en un mosaico (parecido al bikeCard que creó hace un momento).
  4. selector: contiene el conjunto de complementos completo. No es necesario utilizar un componente contenedor, aunque en este caso sí que lo utilizaremos para facilitar la gestión de eventos.

Por ahora, la aplicación utiliza un archivo de datos para cargar datos estáticos para hacer pruebas. En la siguiente unidad aprenderá a obtener datos dinámicos de una organización.

Composición de componentes

Vamos a agregar varios archivos a nuestro proyecto para implementarlos en una organización.

  1. Descargue los archivos para esta aplicación desde aquí: Aplicación de selector de bicicletas para Trailhead.
  2. Descomprima los archivos en la carpeta force-app/main/default/ lwc del proyecto bikeCard. Estructura de archivos de la aplicación del selector de bicicletas.

Relaciones entre los componentes

En esta aplicación, hay múltiples componentes funcionando juntos; y algunos están anidados dentro de otros. Del mismo modo que se anidan unos elementos HTML dentro de otros, se pueden anidar unos componentes web Lightning —que son elementos HTML personalizados— dentro de otros.

En nuestro sistema de archivos, las carpetas de los componentes no nos dicen mucho sobre las relaciones que existen entre ellos.

Veamos ahora en un diagrama cómo están anidados los componentes en el nivel de la interfaz de usuario.

Relaciones principal-secundario entre los componentes de la aplicación del selector de bicicletas.

Si observa los archivos, puede ver que el componente del selector crea la página y representa los componentes de lista(c-list) y detalle(c-detail).

<template>

  <div class="wrapper">

    <header class="header">Select a Bike</header>

    <section class="content">

      <div class="columns">

        <main class="main" >

          <c-list onproductselected={handleProductSelected}></c-list>

        </main>

        <aside class="sidebar-second">

          <c-detail product-id={selectedProductId}></c-detail>

        </aside>

      </div>

    </section>

  </div>

</template>

Actualice detail.html con lo siguiente:

<template>
  <template lwc:if={product}>
    <div class="container">

      <div>{product.fields.Name.value}</div>

      <div class="price">{product.fields.MSRP__c.displayValue}</div>

      <div class="description">{product.fields.Description__c.value}</div>

      <img class="product-img" src={product.fields.Picture_URL__c.value}></img>

      <p>

        <lightning-badge label={product.fields.Material__c.value}></lightning-badge>

        <lightning-badge label={product.fields.Level__c.value}></lightning-badge>

      </p>

      <p>

        <lightning-badge label={product.fields.Category__c.value}></lightning-badge>

      </p>

    </div>

  </template>

  <template lwc:else>

    <div>Select a bike</div>

  </template>

</template>

En detail.html, puede ver la representación condicional (lwc:if={product} y lwc:else). Si no seleccionó ningún elemento de la lista, aparecerá un mensaje en el que se pide al usuario que seleccione uno. Cuando se elija una bicicleta, se mostrará la información sobre ella.

El componente de lista muestra varios componentes de mosaico(c-tile), uno por cada bicicleta que haya en los datos. Este anidamiento se hace en el HTML de cada componente principal. Por ejemplo, el componente de la lista tiene el siguiente HTML, que incluye el componente de mosaico como c-tile.

<template>

  <div class="container">

    <template for:each={bikes} for:item="bike">

      <c-tile key={bike.fields.Id.value} product={bike} ontileclick={handleTileClick}></c-tile>

    </template>

  </div>

</template>

Observe cómo cada iteración del elemento bicicleta genera un nuevo componente de mosaico. Basta con incluir la etiqueta del componente c-tile para crear un componente secundario en cada componente de mosaico. Para definir el estilo se utiliza el "contenedor" de definición de clase div, con lo que puede controlar la disposición de los mosaicos. En list.css verá que encapsula el contenido.

.container { display:flex; flex-direction:row; flex-wrap:wrap; }

La relación principal-secundario es importante, no solo para el diseño de la aplicación, sino también para la gestión de eventos.

Adentrémonos un poco más en la gestión de eventos.

Comunicación de eventos hacia arriba, comunicación de propiedades hacia abajo

En un componente complejo (un componente que contenga varios componentes principales y secundarios), los componentes pueden comunicarse hacia arriba y hacia abajo.

Los componentes principales y secundarios pasan información hacia arriba y hacia abajo.

  1. El componente secundario c-todo-item envía un evento al componente principal c-todo-app. Por ejemplo, el componente secundario puede pasar un objeto de evento al componente principal cuando un usuario hace clic en un botón para que el principal pueda gestionar el evento y cambiar la página actual.
  2. El componente principal c-todo-app pasa una propiedad o invoca un método en el componente secundario. Por ejemplo, el componente principal puede configurar un valor de texto en un componente secundario o invocar un método en el componente secundario.

Veamos cómo funciona esta comunicación.

Pasar información hacia arriba

Se puede pasar información hacia arriba mediante eventos y procesos de escucha de eventos.

El componente secundario envía el evento y el componente principal lo escucha. Al enviar el evento, se crea un objeto de evento que el componente secundario puede pasar al principal. El componente principal tiene un gestor para responder al evento.

Por ejemplo (no cree estos componentes), un componente secundario como este contiene un método nextHandler() que crea un objeto de evento simple mediante CustomEvent() y envía el tipo de evento "next" (siguiente) cuando el usuario hace clic en el botón Next (Siguiente).

// todoItem.js

import { LightningElement } from 'lwc';

  ...

  nextHandler() {

    this.dispatchEvent(new CustomEvent('next'));

  }

}    
Nota

Los tipos de eventos pueden ser cualquier cadena, pero deben ajustarse al estándar de eventos DOM sin mayúsculas, sin espacios y con guiones bajos para separar palabras de ser necesario.

El componente principal escucha el evento con el controlador de eventos en línea con el prefijo 'on'(onnext).

<!-- todoApp.html -->

<template>

  <c-todo-item onnext={nextHandler}></c-todo-item>

</template>

Y pasa el objeto de evento a un gestor de eventos.

// todoApp.js

import { LightningElement } from 'lwc';

export default class TodoApp extends LightningElement {

  ... 

  nextHandler(){ 

    this.page = this.page + 1;

  }

} 

Pasar información hacia abajo

Se puede pasar información hacia abajo mediante propiedades públicas y métodos públicos.

Puede hacer que una propiedad de un componente sea pública colocándole delante el decorador @api. A continuación, establezca la propiedad pública por un componente externo.

Por ejemplo (no cree estos componentes), si el componente secundario c-todo-item contiene lo siguiente:

// todoItem.js

import { LightningElement, api } from 'lwc';

export default class TodoItem extends LightningElement {

  @api itemName;

}

Configure el valor del componente principal con lo siguiente:

<!-- todoApp.html -->

<template>

  <c-todo-item item-name="Milk"></c-todo-item>

</template>

Observe que la variable itemName se establece con el atributo en Kebab case item-name. Los nombres de propiedades en JavaScript están en Camel Case, mientras que los nombres de atributos HTML están en Kebab Case (separados-con-guiones) para que coincidan con los estándares HTML. El atributo item-name en el marcado se corresponde con la propiedad de JavaScript itemName.

Las propiedades públicas son excelentes soluciones para pasar hacia abajo valores primitivos, objetos sencillos y matrices.

También puede utilizar métodos de obtención y reguladores para ejecutar cierta lógica cuando las propiedades son obtener o establecer. Y recuerde que deben estar precedidas por el decorador @api para que sean públicas para otros componentes.

También puede crear métodos públicos a los que se puede llamar desde un componente principal. Cree un método público en el componente secundario definiéndolo con el decorador @api y, a continuación, llámelo desde el componente principal.

Supongamos que tenemos un componente secundario como este (no cree estos componentes).

// videoPlayer.js

import { LightningElement, api } from 'lwc';

export default class VideoPlayer extends LightningElement {

  @api play() {

    // Play music!

  }

}

Cuando el componente c-video-player se incluye en un componente principal, podemos invocar el método desde el componente principal así:

// methodCaller.js

import { LightningElement } from 'lwc';

export default class MethodCaller extends LightningElement {

  handlePlay() {

    this.template.querySelector('c-video-player').play();

  }

}

Definimos un método handlePlay() que desencadena el evento. Entonces utilizamos el método DOM querySelector() para buscar un elemento DOM denominado c-video-player e invocamos su método público.

Gestionar eventos en HTML

Nuestra aplicación de selector tiene que gestionar un tipo de evento: el que un usuario haga clic en un mosaico. Cuando esto ocurre, el componente de detalles debería volver a representarse con la información sobre el mosaico en cuestión. Puede gestionar eventos en HTML (agregar un proceso de escucha de eventos en la plantilla) o en JavaScript (programar una función de proceso de escucha de eventos). Recomendamos utilizar la opción con HTML, tal como indicamos a continuación.

Cada componente de mosaico escucha el clic del usuario porque el HTML del componente de mosaico (tile.html) contiene un proceso de escucha de eventos onclick.

<template>

  <div class="container">

    <a onclick={tileClick}>

      <div class="title">{product.fields.Name.value}</div>

      <img class="product-img" src={product.fields.Picture_URL__c.value}></img>

    </a>

  </div>

</template>

Cuando un usuario hace clic en una de las instancias de mosaico en la interfaz de usuario, el proceso de escucha de onclick llama a la función de gestor tileClick en el archivo JavaScript tile.js.

import { LightningElement, api } from 'lwc';

export default class Tile extends LightningElement { 

  @api product; tileClick() { 

    const event = new CustomEvent('tileclick', { 

      // detail contains only primitives detail: this.product.fields.Id.value

    }); 

    // Fire the event from c-tile this.dispatchEvent(event);

  }

} 

Patrón de eventos de la aplicación del selector

En nuestra aplicación del selector de productos utilizamos un componente complejo (uno que contiene varios componentes principales y secundarios). Recomendamos que propague el evento hacia arriba a través de la jerarquía de componentes, de forma que los componentes principales puedan responder a eventos secundarios. Si tiene otros componentes secundarios (no el que desencadena el evento), puede pasar una propiedad hacia abajo a los componentes secundarios en respuesta al evento.

El patrón tiene este aspecto:

Flujo de eventos a través de la jerarquía de componentes.

Para hacer esto, debemos encadenar procesos de escucha de eventos y gestores hacia arriba, hasta el componente de bicicletas eléctricas. A continuación, hay que pasar una propiedad hacia abajo al componente de detalles.

En nuestros archivos, verá lo siguiente.

  1. tile.html tiene el proceso de escucha de eventos onclick que llama al controlador tileClick.
  2. tile.js tiene el método tileClick que crea un nuevo CustomEvent con el tipo de evento tileclick y un objeto que contiene un valor de detail (detalle) (this.product.fields.Id.value).
  3. list.html tiene el proceso de escucha de eventos ontileclick que llama al controlador handleTileClick.
  4. list.js tiene el método handleTileClick que pasa el evento (evt) para crear otro CustomEvent(productselected) con un objeto que también contiene un valor de detail (detalle) evt.detail. Y envía el evento en JavaScript:

    // Fire the event from c-list
    this.dispatchEvent(event);

  5. selector.html tiene el proceso de escucha de eventos onproductselected que llama al controlador handleProductSelected.
  6. selector.js tiene el método handleProductSelected establecido en selectedProductId en el valor evt.detail pasado en él. La variable "selectedProductId" se pasa del componente del selector al componente de detalles en selector.html:
    product-id={selectedProductId}.
  7. detail.html tiene una directiva condicional (¿recuerda las directivas condicionales de la Unidad 2?) que espera un valor de producto:
    <template lwc:if={product}>
  8. detail.js combina las distintas partes. Crea una variable privada _productId para hacer el seguimiento del estado del valor productId. A continuación, utiliza un patrón get/set para obtener el valor y establecerlo en una variable product que deja que detail.html cargue el contenido condicional.

Los métodos reguladores y de obtención son una construcción habitual de JavaScript. Le permiten añadir lógica y condiciones a las asignaciones de propiedades.

import { LightningElement, api } from 'lwc';

import { bikes } from 'c/data';

export default class Detail extends LightningElement {

  Product;

  // Private var to track @api productId 

  _productId = undefined; 

  // Use set and get to process the value every time it's 

  // requested while switching between products 

  set productId(value) { 

    this._productId = value; 

    this.product = bikes.find(bike => bike.fields.Id.value === value); 

  } 

  // getter for productId 

  @api get productId(){ 

    return this._productId; 

  } 

}

El proceso se repite cada vez que haga clic en un mosaico.

Nota

Los eventos tienen propiedades para gestionar la propagación del evento hacia arriba dentro del árbol DOM. Puede leer más sobre ellos en Configurar la propagación de eventos. Para cambiar los valores predeterminados es necesario ser un usuario avanzado en gestión de eventos y realizar pruebas para verificar que se cumple el comportamiento esperado.

Implementar sus archivos en su organización

Implementemos estos nuevos archivos del proyecto bikeCard en su organización para ver su funcionamiento. Repita los mismos pasos que realizó en la unidad anterior para implementar sus nuevos archivos, abra la organización y cree una página en el Generador de aplicación Lightning con esta aplicación.

  1. En el proyecto bikeCard en VS Code, haga clic con el botón secundario en la carpeta force-app/main/default y seleccione SFDX: Implementar fuente en organización.
  2. Desde la paleta de comandos en VS Code, use SFDX: Abrir organización predeterminada para abrir su organización.
  3. Cree una página con una única región utilizando el componente del selector.
  4. Asígnele la etiqueta Your Bike Selection (Su selección de bicicletas).
  5. Arrastre su componente selector a la parte superior del diseño de página.
  6. Guárdelo y actívelo para todos los usuarios.
  7. Ábralo y vea cómo funciona su componente en la interfaz de usuario.

Ya tiene una página completamente interactiva formada por varios componentes que funcionan juntos. A continuación, vamos a experimentar con los estilos y con la obtención de datos en vivo desde una organización.

Recursos

¡Siga aprendiendo gratis!
Regístrese para obtener una cuenta y continuar.
¿Qué hay para usted?
  • Consiga recomendaciones personalizadas para sus objetivos profesionales
  • Practique sus aptitudes con retos prácticos y pruebas
  • Siga y comparta su progreso con empleadores
  • Póngase en contacto para recibir asesoramiento y oportunidades laborales