Explicaciones sobre la declaración de manejadores de eventos dentro de los templates de Lit. Ejemplo de componentes y métodos que hacen de manejadores de eventos, usando el objeto evento y otras particularidades de Javascript.
Aunque en artículos anteriores del Manual de Lit ya hemos hablado sobre eventos y hemos visto cómo se asocian manejadores en templates, vamos a realizar un componente para explorar un poco más esta característica fundamental de la creación de componentes.
Qué son eventos, manejadores y el objeto evento
Vamos a comenzar con un poco de cultura general en torno a conceptos que necesitamos manejar para entender este apartado dedicado a eventos.
En general, los eventos son sucesos que ocurren durante el uso de una aplicación informática. Mediante programación somos capaces de detectar esos sucesos y realizar acciones cuando se produzcan.
Los manejadores de eventos son las funciones que asociamos a los eventos, de modo que cuando se produzcan somos capaces de especificar qué código debe ejecutarse. La invocación a los manejadores de eventos se realiza automáticamente por Javascript cuando son capturados los eventos.
El objeto evento en Javascript se recibe en toda función manejadora de evento. Al invocarse al manejador, Javascript crea por nosotros ese objeto evento y lo manda como parámetro al manejador del evento. El objeto evento es capaz de ofrecer mucha información sobre las características del evento que se ha capturado. Además nos ofrece algunos métodos que podemos invocar para hacer cosas con ese evento en particular.
Suponemos que a estas alturas más o menos están claras estas cuestiones, pero si no es así os recomiendo leer el artículo de eventos en Javascript, ya que las aborda con más detalle y ejemplos. Todo lo que se explica en ese artículo aplica directamente a Lit, dado que el desarrollo con Web Components y Lit no es más que Javascript.
Cómo definir manejadores de evento en templates Lit
Los manejadores de evento se pueden asociar a cualquiera de los elementos del template, ya sean etiquetas HTML normales o incluso componentes Lit. Para ello usamos la siguiente sintaxis:
render() {
return html`
<span>
<a href="#" @click=${funcionManejadora}>Enlace…</a>
</span>`;
}
Mediante la "@
" indicamos que se va a asociar un manejador de evento. El tipo del evento se coloca a continuación de la arroba, en este caso es @click
, que quiere decir que es un evento que capturará los clics sobre la etiqueta <a>
, que es donde estamos colocando el manejador.
Luego asignamos la función que va a hacer de manejadora de eventos. Puede ser una función común tal cual estamos viendo en este ejemplo.
function funcionManejadora(e) {
e.preventDefault();
console.log('Soy el manejador de click sobre el enlace!!');
}
Como puedes ver, la función manejadora recibe un parámetro automáticamente, en este caso lo hemos nombrado "e
". Ese es el objeto evento. En este ejemplo hemos usando el objeto evento para prevenir el comportamiento por defecto de los enlaces, que es viajar a una nueva dirección. Así que ese enlace no nos llevará a ningún sitio si lo pulsamos y simplemente mostrará un mensaje en la consola.
En el ejemplo anterior hemos usado una función común como maneadora de evento, pero en realidad lo normal en el desarrollo de componentes es que los manejadores de eventos sean métodos del propio componente. No es necesario, pero sí común. En el caso de que los manejadores sean métodos del propio componente, tenemos que referirnos a ellos usando this
al asociar el manejador del evento.
<a href="${this.tag.url}" @click=${this.metodoManejador}>Enlace…</a>
Entonces, el método se define en la clase del componente, pudiendo recibir igualmente el objeto evento. La ventaja de esta posibilidad es que dentro del método del componente podemos acceder al propio componente en el que estamos trabajando.
metodoManejador(e) {
e.preventDefault();
console.log('Soy el componente', this);
}
Gracias al acceso a this
, dentro de un manejador podemos acceder a las propiedades del componente, así como a otros métodos del componente.
metodoManejador() {
if(this.tag.name == 'Lit') {
console.log('Mi propiedad name es Lit');
}
}
Observarás que en el ejemplo anterior no hemos recibido el objeto evento. Si no vas a hacer nada con él no necesitas declarar el parámetro.
Ejemplo de input con característica de validación
Vamos a realizar un componente nuevo para poder mostrar un ejemplo un poco más elaborado de eventos, de modo que podamos practicar con nuevos componentes y otros eventos más allá de "click".
Nuestro ejemplo de hoy consiste en un componente de campo de texto que permite introducir un email. El componente muestra mensajes de validación cuando el email se escribe de manera incorrecta, es decir, cuando aquello que se ha escrito en el campo de texto no es un email.
Vamos a comenzar por la parte que nos interesa, que consiste en mostrar el template para que veamos cómo se declaran dos eventos sobre el campo input.
render() {
return html`
<input
type="text"
id="email"
@focus=${this.clearMessage}
@blur=${this.validateInput}
>
<div class="msg">${this._validationMessage}</div>
`;
}
Como puedes ver, puedes asociar tantos manejadores de eventos como sean necesarios a los elementos del componente. En este caso hemos asociado manejadores a los eventos "focus" y "blur", que se disparan cuando el usuario pone el foco de la aplicación en la caja de texto y cuando el usuario saca el foco de la aplicación del campo de texto.
Como puedes deducir del anterior template nuestro componente realizará las correspondientes validaciones cuando el usuario retira el foco de la aplicación del campo de texto (blur). Al poner el foco en el campo de texto se eliminarán los mensajes de posibles errores de validación, esperando que el usuario escriba un email.
Manejador para el evento focus
El manejador para el evento "focus" simplemente cambia el mensaje de validación que aparece al lado del campo de texto.
clearMessage() {
this._validationMessage = 'Escribe un email';
}
De este modo, cada vez que el usuario coloca el cursor en el campo de texto, supuestamente para escribir algo, en el mensaje le informamos que lo que tiene que escribir es un email.
Manejador para el evento blur
Ahora veamos el manejador para el evento "blur", que es el que realiza la validación. Este es especialmente interesante porque nos va a permitir aprender algo nuevo que no habíamos visto hasta el momento en el Manual de Lit, el acceso de manera programática a los elementos del template.
El objetivo de este manejador consiste en leer lo que haya escrito en el campo de texto para saber si realmente es un email. Pues bien, si queremos acceder al campo de texto necesitamos usar Javascript y podríamos hacerlo de varias maneras, pero vamos a mostrar un bien sencilla, que básicamente consiste en acceder al elemento por su identificador.
Observa en el código del template del componente, que mostramos antes, que le habíamos puesto un id="email"
. Pues nosotros podemos acceder a ese elemento de esta manera:
let campoTexto = this.shadowRoot.getElementById('email');
En el anterior código:
- this es el componente que estamos desarrollando
- shadowRoot hace referencia al Shadow DOM del componente, su DOM interno.
- getElementById() es el método nativo de Javascript que usamos para acceder al objeto del DOM de un elemento del que tenemos su id.
Todo lo anterior forma parte de Javascript. Es decir, usamos el propio estándar de Web Components para acceder a elementos del template.
No hemos explicado mucho acerca del estándar de Web Components, pero puedes encontrar información detallada en otros artículos. En este punto posiblemente te interesará saber más sobre el Shadow DOM.
Una vez tengo el campo de texto, con .value
puedo acceder a lo que hay escrito dentro.
Ahora veamos el código del manejador que nos ocupa, que se encarga de realizar las validaciones.
validateInput() {
let text = this.shadowRoot.getElementById('email').value;
if( text == '') {
this._validationMessage = "Escribe un email";
} else {
if(this.validateEmail(text)) {
this._validationMessage = "Correcto!";
} else {
this._validationMessage = "Ese email no es válido";
}
}
}
- Accede en un primer paso al texto del input
- Verifica si había algo escrito. Si no es así, simplemente indica que se debe escribir el email.
- Si había algo escrito verifica si es un email válido. En caso positivo escribe un mensaje indicando que está correcto y en caso negativo indica que no es un email válido.
El código del componente completo lo puedes ver a continuación.
import { LitElement, html, css } from 'lit';
export class DwInputEmail extends LitElement {
static styles = [
css`
:host {
display: block;
}
.msg {
font-size: 0.8rem;
}
`
];
static properties = {
_validationMessage: { type: String }
}
constructor() {
super();
this.clearMessage();
}
render() {
return html`
<input
type="text"
id="email"
@focus=${this.clearMessage}
@blur=${this.validateInput}
>
<div class="msg">${this._validationMessage}</div>
`;
}
clearMessage() {
this._validationMessage = 'Escribe un email';
}
validateInput() {
let text = this.shadowRoot.getElementById('email').value;
if( text == '') {
this.clearMessage();
} else {
if(this.validateEmail(text)) {
this._validationMessage = "Correcto!";
} else {
this._validationMessage = "Ese email no es válido";
}
}
}
validateEmail(email) {
return String(email)
.toLowerCase()
.match( /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
);
};
}
customElements.define('dw-input-email', DwInputEmail);
Hemos podido aprender a crear un componente input con validación. Es un componente sencillo pero que podría ser muy útil en múltiples aplicaciones. Por supuesto, una vez lo hemos desarrollado lo podremos reutilizar todas las veces que lo necesitemos, en cualquier tipo de proyecto donde se pueda usar Javascript.
Miguel Angel Alvarez
Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...