Implementando filter como operador en Observables
Feb 24, 2022

Implementando filter como operador en Observables

🚀 Implementando filter 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. 🎯

📖 Ejemplo de filter en Arrays

Veamos 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.

🎩 Implementando 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 aprendido
  1. Implementa un Observable que filtre y muestre los eventos de scroll del usuario en una página web, pero solo cuando el desplazamiento es hacia arriba.
  2. 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.
  3. Combina los operadores filter y map para crear un Observable que detecte eventos de mousemove y 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.
  4. Utiliza la función filter en 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.
  5. 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

Sebastian Gomez

Creador de contenido principalmente acerca de tecnología.

Leave a Reply

0 Comments

Related Posts

Categorias