Cómo implementar type ahead con Observables y RxJS

Clase 69 de 80Curso de Angular 4

Resumen

Implementar un type ahead con Observables en Angular y RxJS permite sugerir direcciones en tiempo real consultando la API de Google Maps. Aquí se explica, paso a paso, cómo estructurar el stream, aplicar operadores como switchMap y map, y vincular el campo de entrada con un FormControl, siguiendo buenas prácticas y sin código global.

¿Cómo funciona el type ahead con observables en Angular?

El flujo parte de un input controlado por FormControl. Cada tecla del usuario emite un valor en el stream de valueChanges, que tratamos con operadores de RxJS. Con switchMap hacemos una petición HTTP por cada cambio y desechamos anteriores; con map transformamos la respuesta a JSON y extraemos la propiedad results que devuelve Google.

  • Observables y RxJS: modelan cambios del input como un stream continuo.
  • Operador switchMap: intercambia la suscripción activa por la última consulta.
  • Operador map encadenado: primero convierte a response.json(), luego extrae response.results.
  • Convención $: nombrar el stream como results$ para indicar que es observable.
  • Tipos flexibles: usar any cuando el contrato de la API puede cambiar.
  • Buenas prácticas: mover importaciones al componente y evitar código global.
  • Sin jQuery: referenciar el input con FormControl, no con jQuery o JavaScript puro.
  • Template strings: armar la URL con backticks y ${variables} para parámetros de consulta.

¿Cómo configurar FormControl y el stream de resultados?

Primero se declara un searchField como FormControl y un results$ como Observable. En el constructor, se inicializa searchField y se construye el pipeline que escucha valueChanges, llama a http.get con el query y aplica los maps. También se define una constante URL para la ruta del servicio de Google.

import { FormControl } from '@angular/forms';
import { Observable } from 'rxjs/Observable';
// Operadores RxJS agregados a Observable (switchMap, map), según configuración del proyecto

import { Http } from '@angular/http';

export class CrearComponent {
  private searchField: FormControl;
  results$: Observable<any>;

  private URL = '...'; // URL base del servicio de Google.

  constructor(private http: Http) {
    this.searchField = new FormControl();

    this.results$ = this.searchField.valueChanges
      .switchMap(query => this.http.get(`${this.URL}?address=${query}`))
      .map(response => response.json())
      .map(response => response.results);
  }
}

Claves para dominar este paso: - searchField como FormControl: habilita escuchar cambios con valueChanges. - results$ como stream: retorna sugerencias conforme se escribe. - http.get con query: address=query es el parámetro que consume Google. - Encadenamiento de operadores: se pueden usar múltiples map para formatear datos.

¿Por qué usar switchMap en lugar de otras estrategias?

Porque cancela peticiones previas cuando llega una nueva entrada del usuario. Así evitas respuestas obsoletas y mantienes el stream sincronizado con lo último tecleado.

¿Qué conviene tipar y qué dejar como any?

Cuando la estructura exacta de la respuesta de la API puede variar, any reduce fricción. Se mapea lo necesario: response.json() y response.results. Esto simplifica y protege ante cambios del proveedor.

¿Cómo vincular el input con formControl en HTML?

Se crea un contenedor visual y un formulario simple. El input se enlaza con [formControl] para que Angular emita cambios al stream. La interfaz todavía no lista las sugerencias; esa capa visual se añade después, pero el type ahead ya queda operativo a nivel de datos.

<div class="well">
  <form>
    <h3>Buscar dirección en Google Maps</h3>
    <input type="text" [formControl]="searchField" class="form-control">
  </form>
</div>

Puntos importantes del marcado: - [formControl]="searchField": conecta el input con el FormControl de TypeScript. - Estructura mínima: contenedor well, form, encabezado y campo de texto. - Estilos: class="form-control" para mejor presentación.

¿Qué prácticas mejoran la mantenibilidad?

  • Evitar código global: mueve importaciones y lógica al componente donde se usa.
  • Inyección de dependencias: private http: Http dentro del constructor.
  • Separación de responsabilidades: lógica del stream en TypeScript, vista en HTML.

¿Has probado otras combinaciones de operadores para tu type ahead con RxJS? Comparte tu experiencia y dudas en los comentarios.