Łączenie strumienia z flatMap

FlatMap stworzony przez ReactiveX na licencji CC-3 \(http://reactivex.io/documentation/operators/flatmap.html\)

Przypadki FlatMap:

Załóżmy, że chcemy zaimplementować funkcję wyszukiwania AJAX, w której każde naciśnięcie klawisza w polu tekstowym automatycznie wykona wyszukiwanie i zaktualizuje stronę z wynikami. Jak by to wyglądało? Cóż, mamy Observable subskrybowane zdarzenia pochodzące z pola wejściowego, a przy każdej zmianie wejścia chcemy wykonać pewne żądanie HTTP, również Observable, które subskrybujemy.

Używając flatMap możemy przekształcić strumień zdarzeń (zdarzenia keypress w polu tekstowym) do naszego strumienia odpowiedzi (wyniki wyszukiwania z żądania HTTP).

app/services/search.service.ts

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

const SERVER = 'https://books.otwartaedukacja.pl/books';

@Injectable()
export class SearchService {

  constructor(private http: Http) {}

  search(term: string) {
    return this.http.get(SERVER+`?title=${term}`)
      .map(response => { return response.json(); });
  }
}

Tutaj mamy podstawową usługę wyszukiwanie według podanego klucza. Funkcja search zwracaObservable, wykonując pewne podstawowe przetwarzanie (przekształca odpowiedź w obiekt JSON).

Komponent, który będzie korzystał z tej usługi:

app/app.component.ts

import { Component } from '@angular/core';
import { FormControl, 
    FormGroup, 
    FormBuilder } from '@angular/forms'; 
import { SearchService } from './services/search.service';
import 'rxjs/Rx';

@Component({
    selector: 'app-root',
    template: `
        <form [formGroup]="coolForm">
        <input formControlName="search" placeholder="Search book">
        </form>        
        <div *ngFor="let book of result">
          {{book.title}} [{{book.authors}}]
        </div>
    `
})

export class AppComponent {
    searchField: FormControl;
    coolForm: FormGroup;
        result : any;

    constructor(private searchService:SearchService, private fb:FormBuilder) {
        this.searchField = new FormControl();
        this.coolForm = fb.group({search: this.searchField});

        this.searchField.valueChanges
          .debounceTime(400)
            .flatMap(term => this.searchService.search(term))
            .subscribe(result => {
                this.result = result;
            });
    }
}

Zobacz przykład [026]

Tutaj ustawiliśmy podstawowy formularz z pojedynczym polem, search, którego zmiany obserwujemy. Metoda debounceTime wprowadza czas opóźnienia (400ms). Całą "magię" wykonuje flatMap, który łączy dwa strumienie Observables (z formularza i odczytu z serwera) w jeden spójny strumień. Strumień ten możemy wykorzystać do kontrolowania zdarzeń pochodzących z danych wprowadzanych przez użytkownika i odpowiedzi serwera.

Zauważ, że flatMap spłaszcza strumień zapytań do strumienia emitowanych wartości (prosteObservable). Każde naciśnięcie klawisza w polu formularza powoduje natychmiastowe odświeżenie wyników!