Combining Streams with flatMap

FlatMap created by ReactiveX licensed under CC-3 (http://reactivex.io/documentation/operators/flatmap.html)

Figure: FlatMap created by ReactiveX licensed under CC-3 (http://reactivex.io/documentation/operators/flatmap.html)

A case for FlatMap:

By using flatMap we can transform our event stream (the keypress events on the text field) into our response stream (the search results from the HTTP request).

app/services/search.service.ts

  1. import {Http} from '@angular/http';
  2. import {Injectable} from '@angular/core';
  3. @Injectable()
  4. export class SearchService {
  5. constructor(private http: Http) {}
  6. search(term: string) {
  7. return this.http
  8. .get('https://api.spotify.com/v1/search?q=' + term + '&type=artist')
  9. .map((response) => response.json())
  10. }
  11. }

Here we have a basic service that will undergo a search query to Spotify by performing a get request with a supplied search term. This search function returns an Observable that has had some basic post-processing done (turning the response into a JSON object).

OK, let's take a look at the component that will be using this service.

app/app.component.ts

  1. import { Component } from '@angular/core';
  2. import { FormControl,
  3. FormGroup,
  4. FormBuilder } from '@angular/forms';
  5. import { SearchService } from './services/search.service';
  6. import 'rxjs/Rx';
  7. @Component({
  8. selector: 'app-root',
  9. template: `
  10. <form [formGroup]="coolForm"><input formControlName="search" placeholder="Search Spotify artist"></form>
  11. <div *ngFor="let artist of result">
  12. {{artist.name}}
  13. </div>
  14. `
  15. })
  16. export class AppComponent {
  17. searchField: FormControl;
  18. coolForm: FormGroup;
  19. constructor(private searchService:SearchService, private fb:FormBuilder) {
  20. this.searchField = new FormControl();
  21. this.coolForm = fb.group({search: this.searchField});
  22. this.searchField.valueChanges
  23. .debounceTime(400)
  24. .flatMap(term => this.searchService.search(term))
  25. .subscribe((result) => {
  26. this.result = result.artists.items
  27. });
  28. }
  29. }

View Example

Here we have set up a basic form with a single field, search, which we subscribe to for event changes.We've also set up a simple binding for any results coming from the SearchService.The real magic here is flatMap which allows us to flatten our two separate subscribed Observablesinto a single cohesive stream we can use to control events coming from user input and from server responses.

Note that flatMap flattens a stream of Observables (i.e Observable of Observables) to a stream of emitted values (a simple Observable), by emitting on the "trunk" stream everything that will be emitted on "branch" streams.

原文: https://angular-2-training-book.rangle.io/handout/http/search_with_flatmap.html