Sebastian Gomez
Implementando filter como operador en Observables
🚀 Implementandofilter como operador en Observables 🎛️En este post, vamos a 🔎 explorar cómo aumentar el número de operadores en un Observable añadiendo el operador map. 🌐
Recordemos del post anterior, donde implementamos el operador map en observables desde cero, de manera similar a como lo hace RX.js. Ahora, vamos a incrementar la cantidad de operadores que podemos usar en un Observable. 📈
Primero, echemos un vistazo a la definición más pura de un Observable con una función generadora de observables a partir de eventos:
// Define una clase llamada Observable
class Observable {
// El constructor de la clase recibe una función de suscripción
constructor(subscribe) {
// Almacena la función de suscripción en una propiedad privada
this._subscribe = subscribe;
}
// Método para suscribir un observador al observable
subscribe(observer) {
// Ejecuta la función de suscripción con el observador proporcionado
return this._subscribe(observer);
}
// Método estático que crea un observable a partir de un evento del DOM
static fromEvent(domElement, eventName) {
// Retorna una nueva instancia de Observable
return new Observable(function subscribe(observer) {
// Define un manejador de eventos que invoca el método next del observador con el evento
const handler = (ev) => {
observer.next(ev);
};
// Añade el manejador de eventos al elemento del DOM para el nombre del evento dado
domElement.addEventListener(eventName, handler);
// Retorna un objeto con un método para cancelar la suscripción al evento
return {
unsubscribe() {
// Elimina el manejador de eventos del elemento del DOM
domElement.removeEventListener(eventName, handler);
},
};
});
}
}
Con esto, puedes crear Observables que devuelven información del evento de la siguiente manera:
// Obtiene una referencia al botón con ID "button" del documento HTML
const button = document.getElementById("button");
// Crea un observable llamado "clicks" utilizando el método estático "fromEvent" de la clase Observable,
// suscribiendo al botón al evento "click"
const clicks = Observable.fromEvent(button, "click");
// Suscribe un objeto observador al observable "clicks" y almacena la suscripción en "clicksSubscription"
const clicksSubscription = clicks.subscribe({
// Define el método "next" del objeto observador para manejar eventos de clic en el botón
next(e) {
// Registra en la consola un mensaje indicando que se hizo clic en el botón y muestra el objeto del evento "e"
console.log("Click in the button", e); // "e" contiene toda la información del evento
}
});
// Cancela la suscripción a eventos de clic en el botón utilizando el método "unsubscribe" del objeto de suscripción
clicksSubscription.unsubscribe(); // Así te puedes des-suscribir
Pero, a veces necesitamos realizar más operaciones sobre la cadena de datos. Por ejemplo, si queremos obtener sólo algunos datos del evento, como la posición del Mouse 🖱️, o si sólo queremos escuchar los clicks que se hagan en la parte izquierda del botón. Para ello, vamos a implementar la función filter sobre Observables. 🎯
filter en ArraysVeamos cómo funciona filter en Arrays de JavaScript antes de implementarlo en Observables:
[1, 2, 3, 4].filter((x) => x > 3);
// retorna [4]filter, al igual que map, recibe una función como parámetro. Esta función es de validación y retorna true o false. El operador filter devuelve el elemento para el cual la función de validación es true.
filter en Observables// Define un método "filter" que toma una función de validación como argumento
filter(validationFunction) {
// Almacena una referencia al objeto actual en la variable "self"
const self = this;
// Retorna un nuevo observable
return new Observable(function subscribe(observer) {
// Suscribe un objeto observador al observable actual ("self") y almacena la suscripción en "subscription"
const subscription = self.subscribe({
// Define el método "next" del objeto observador para manejar los valores emitidos por el observable
next(v) {
// Si la función de validación retorna verdadero para el valor "v", pasa el valor al método "next" del observador
if(validationFunction(v)) {
observer.next(v);
}
},
// Define el método "error" del objeto observador para manejar errores emitidos por el observable
error (e) {
// Pasa el error "e" al método "error" del observador
observer.error(e);
},
// Define el método "complete" del objeto observador para manejar la finalización del observable
complete () {
// Llama al método "complete" del observador
observer.complete();
}
});
// Retorna la suscripción
return subscription;
});
}
Ahora veamos cómo usar el operador filter en Observables para filtrar los clicks que se hacen en la parte izquierda del botón:
// Obtiene una referencia al botón con ID "button" del documento HTML
const button = document.getElementById("button");
// Crea un observable llamado "clicks" utilizando el método estático "fromEvent" de la clase Observable,
// suscribiendo al botón al evento "click"
const clicks = Observable.fromEvent(button, "click");
// Filtra y transforma los eventos de clic antes de suscribir un objeto observador
const clicksSubscription = clicks
// Aplica el método "filter" para permitir solo eventos en los que la posición X del mouse sea menor a 40
.filter((ev) => ev.offsetX < 40)
// Aplica el método "map" para transformar el evento en su posición X del mouse (offsetX)
.map((ev) => ev.offsetX)
// Suscribe un objeto observador a los eventos filtrados y transformados
.subscribe({
// Define el método "next" del objeto observador para manejar eventos de clic en el botón
next(offSetX) {
// Registra en la consola un mensaje indicando la posición X del mouse en el momento del clic
console.log("La posición del mouse respecto a X " + offSetX); // Solo imprime si haces click a la izquierda de "Me"
},
});
Aquí tienes el ejemplo completo con la implementación de `filter` y `map`:
🔗 [https://codepen.io/seagomezar/pen/WdVzxB](https://codepen.io/seagomezar/pen/WdVzxB)
✍️ Conclusiones
1. Hemos aprendido a implementar el operador `filter` en Observables para filtrar y procesar los eventos que cumplan con ciertos criterios. 🎉 2. Los operadores en Observables, como `filter` y `map`, permiten manipular y realizar operaciones sobre la cadena de datos de manera más eficiente. 🛠️ 3. Los operadores sobre Observables siguen una lógica similar y, en su mayoría, deben retornar un nuevo Observable. Las operaciones o filtros sobre los valores se realizan en la función `next`. 🔄
🏋️ Ejercicios para practicar
1. Crea un Observable que filtre y muestre solo los clicks realizados con el botón derecho del mouse. 2. Implementa un Observable que filtre y muestre solo los eventos de teclado con teclas de flechas (arriba, abajo, izquierda y derecha). 3. Combina los operadores `filter` y `map` para crear un Observable que filtre eventos de teclado y transforme la salida en un objeto que contenga información relevante sobre la tecla presionada (por ejemplo, el nombre de la tecla y si fue presionada con alguna tecla modificadora como Shift, Ctrl, etc.).
🔝 **Resumen en 3 puntos**:
1. Aprendimos a implementar y utilizar el operador `filter` en Observables. 2. Entendimos cómo funcionan los operadores en Observables, como `filter` y `map`, para manipular eventos. 3. Vimos ejemplos de cómo aplicar `filter` y `map` en casos de uso reales, como filtrar clicks y eventos de teclado
💡 Ideas adicionales para aplicar lo aprendidoImplementa un Observable que filtre y muestre los eventos de
scrolldel usuario en una página web, pero solo cuando el desplazamiento es hacia arriba.Crea un Observable que detecte y muestre eventos de cambio (
change) en un formulario, pero solo cuando el valor ingresado cumpla con ciertas condiciones, como una longitud mínima o un formato específico.Combina los operadores
filterymappara crear un Observable que detecte eventos demousemovey transforme la salida en un objeto que contenga información relevante sobre la posición del mouse en porcentajes respecto al ancho y alto de la ventana.Utiliza la función
filteren Observables para implementar un sistema de autocompletado que muestre sugerencias en función de la entrada del usuario en un campo de texto, pero solo cuando el usuario haya escrito al menos tres caracteres.Implementa un Observable que filtre y muestre eventos de cambio en el tamaño de la ventana (
resize), pero solo cuando la diferencia entre el tamaño anterior y el nuevo tamaño sea mayor a un valor específico.
Estas ideas adicionales te ayudarán a aplicar y consolidar lo aprendido en el post sobre la implementación de filter en Observables. No olvides que puedes combinar diferentes operadores para lograr resultados más complejos y adaptados a tus necesidades. ¡Buena suerte en tus proyectos y sigue explorando las posibilidades que ofrecen los Observables! 🚀
Sebastian Gomez
Creador de contenido principalmente acerca de tecnología.