Tutorial de ReactiveX – Ampliando los observables
Ampliando los observables
En la entrada anterior del tutorial de ReactiveX realizamos una breve introducción a la librería y creamos algunos ejemplos sencillos.
A continuación mostraremos algunas de las múltiples funciones que ofrece ReactiveX para crear observables.
- of(): Se crean observables a partir de strings, arrays, objetos, boolean, etc…, emitiendo cada argumento secuencialmente y de forma síncrona hasta que recorra todos los argumentos.
-
import { Observer, of } from 'rxjs'; const observerCfg: Observer<any> = { next: response => { let res = null res = typeof response === 'object' || Array.isArray(response) ? JSON.stringify(response) : response; if (typeof response === 'function') { res(); } console.log(`Response: ${res}`); }, error: err => { console.log(`Error: ${err}`); }, complete: () => { console.log(`Finalizado`); } }; const obsNumber$ = of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); const obsString$ = of('a', 'b', 'c', 'name', 'age'); const obsArray$ = of([1, 2, true, 'a'], ['a', 'b'], [true, false]); const obsObject$ = of({ a: 1, b: 2 },{ a: { b: { c: 1} } }); const obsFunc$ = of(() => alert('1'), () => alert('2')); obsNumber$.subscribe(observerCfg); obsString$.subscribe(observerCfg); obsArray$.subscribe(observerCfg); obsObject$.subscribe(observerCfg); obsFunc$.subscribe(observerCfg);
-
- from(): Se comporta igual que la función of(), salvo que from() emite los elementos que están dentro del argumento.
-
// Importamos los observables de la librería ReactiveX import { from, Observer, of } from 'rxjs'; const observerCfg: Observer<any> = { next: response => { let res = null res = typeof response === 'object' || Array.isArray(response) ? JSON.stringify(response) : response; if (typeof response === 'function') { res(); } console.log(`Response: ${res}`); }, error: err => { console.log(`Error: ${err}`); }, complete: () => { console.log(`Finalizado`); } }; const observerFrom$ = from('abcdefgh'); const observerOf$ = of('abcdefgh'); observerFrom$.subscribe(observerCfg); // Response: a, Response: b, Response: c, Response: d, Response: e, Response: f, Response: g, Response: h // Emite cada elemento dentro del argumento observerOf$.subscribe(observerCfg); // Response: abcdefgh // Emite el argumento
-
- fromEvent(): Podemos crear observables que emiten cuando los eventos de Javascript son ejecutados, encargándose también de cancelar la escucha del evento cuando se cancele la suscripción del observable.
-
// Importamos los observables de la librería ReactiveX import { Observer, fromEvent } from 'rxjs'; const observerCfg: Observer<any> = { next: response => { console.log('Response:'); console.log(response?.key || response?.x || ''); }, error: err => { console.log(`Error: ${err}`); }, complete: () => { console.log(`Finalizado`); } }; const mouseEvent$ = fromEvent<MouseEvent>(document, 'click'); const keybEvent$ = fromEvent<KeyboardEvent>(document, 'keydown'); mouseEvent$.subscribe(observerCfg); // Response: 300 -> Coordenada X del evento mouse keybEvent$.subscribe(observerCfg); // Response: a -> key del evento keyboard
-
- range(): Creamos un observable que emite un listado de números ascendentes comprendidos entre la posición inicial y un número de veces determinado.
-
// Importamos los observables de la librería ReactiveX import { asyncScheduler, Observer, range } from 'rxjs'; const observerCfg: Observer<any> = { next: response => { console.log('Response:', response); }, error: err => { console.log(`Error: ${err}`); }, complete: () => { console.log(`Finalizado`); } }; // Síncrono console.log('IN RANGE A'); const rangeA$ = range(1, 20); // 1,2,3....,20 const subscriptionA = rangeA$.subscribe(observerCfg); console.log('OUT RANGE A'); // Síncrono console.log('IN RANGE B'); const rangeB$ = range(20); // 0,1,2....,19 const subscriptionB = rangeB$.subscribe(observerCfg); console.log('OUT RANGE B'); // Forzamos asíncrono console.log('IN RANGE C'); const rangeC$ = range(-10, 20, asyncScheduler); // -10,-9,-8....,9 const subscriptionC = rangeC$.subscribe(observerCfg); console.log('OUT RANGE C');
-
- interval(): Creamos un observable que emite un listado de números ascendentes con un intervalo entre cada emisión que podemos indicar.
-
// Importamos los observables de la librería ReactiveX import { Observer, interval } from 'rxjs'; const observerCfg: Observer<any> = { next: response => { console.log('Response:', response); }, error: err => { console.log(`Error: ${err}`); }, complete: () => { console.log(`Finalizado`); } }; const interval$ = interval(2000); // Emitimos un valor cada 2 seg. interval$.subscribe(observerCfg);
-
- timer(): Es similar a interval(), pero a timer() ademas nos permite retrasar el inicio de la emisión del listado los números.
-
// Importamos los observables de la librería ReactiveX import { Observer, timer } from 'rxjs'; const observerCfg: Observer<any> = { next: response => { console.log('Response:', response); }, error: err => { console.log(`Error: ${err}`); }, complete: () => { console.log(`Finalizado`); } }; const date = new Date(); const timer$ = timer(2000); // Espera 2 segundos y emite un valor const timerInterval$ = timer(2000, 500); // Espera 2 segundos y emite un valor cada 0.5 seg. const alarm$ = timer(date); // Emite en una fecha determinada timer$.subscribe(observerCfg); timerInterval$.subscribe(observerCfg); alarm$.subscribe(observerCfg);
-
- ajax(): Creamos un observable que realiza peticiones Ajax y nos devuelve la respuesta de la petición.
-
// Importamos los observables de la librería ReactiveX import { Observer } from 'rxjs'; import { ajax } from 'rxjs/ajax'; const observerCfg: Observer<any> = { next: response => { console.log('Response:', response); }, error: err => { console.log(`Error: ${err}`); }, complete: () => { console.log(`Finalizado`); } }; const url = 'https://jsonplaceholder.typicode.com/users'; const ajax$ = ajax(url); const subscription = ajax$.subscribe(observerCfg);
-
Con los ejemplos anteriores hemos ampliado el conocimiento en ReactiveX, pero sería interesante poder aplicar lo que hemos aprendido hasta ahora en un ejemplo mas útil.
Actualizando el DOM usando ReactiveX
El siguiente ejemplo es muy sencillo pero nos da una pista hasta donde podemos llegar con ReactiveX.
index.html
<body> <h1>Turorial ReactiveX</h1> <input type="text" placeholder="name" data-reactive="keyup" data-source="name" /> <input type="number" placeholder="age" data-reactive="keyup" data-source="age" /> <div> <div data-model="name"></div> <div data-model="name"></div> <div data-model="name"></div> <div> <input type="text" readonly data-model="name" /> </div> <div data-model="age"></div> <div data-model="age"></div> <div> <input type="text" readonly data-model="age" /> </div> </div> <script src="bundle.js"></script> </body>
index.ts
import { fromEvent, Observer } from 'rxjs'; const keyboardCallback: Observer<any> = { next: response => { // Obtenemos el modelo que necesitamos actualizar const source = response.target.dataset.source; // Buscamos todos los modelos que necesitamos actualizar const updateModels = document.querySelectorAll(`[data-model="${source}"]`); // Empezamos a recorrer cada elemento y actualizamos su contenido updateModels.forEach(item => { const hasHTML = ['DIV'].includes(item.tagName); item[hasHTML ? 'innerHTML' : 'value'] = response.target.value; }); }, error: err => {}, complete: () => {} }; // Obtenemos todos los elementos que tenga el siguiente atributo const keyboardEvent = document.querySelectorAll('[data-reactive="keyup"]'); // Creamos un observable sobre los elementos anteriores const keyboardEvent$ = fromEvent<KeyboardEvent>(keyboardEvent, 'keyup'); // Nos suscribimos, y se ejecuta cada vez que presionamos y soltamos una tecla keyboardEvent$.subscribe(keyboardCallback);
En la próxima entrada del tutorial continuaremos aprendiendo mas sobre esta fantástica librería, y recordad que desde aquí podéis acceder a todo el código del tutorial.