angular - Hvilken operator brukes for å koble Observables betinget?


Jeg vil gjerne laste inn noen data, som er sideinndelt, fra en REST API, inn i min Angular-app. Vanligvis sender API-en meg data i følgende struktur:

{
    "next": null,
    "results": [
        {"id": 7, "name": "Alicia"},
        {"id": 8, "name": "Ted"},
        {"id": 9, "name": "Marshall"}
    ]
}

Hvor next er URL-en til GET/ den neste datasideforespørselen. Selvfølgelig vet jeg ikke på forhånd hvor mange sider jeg må iterere for å laste inn dataene fullstendig.

Jeg skrev følgende arbeidende kode for å fullstendig hente dataene (Arbeidende plunker her) :

public loadPeople( next?:string ): void {
    if(!next) next = 'api/1.json';

    this.http.get(next)
        .pipe(
          map( (response: Response) => response.json())
        )
        .subscribe( (data: any) => {
          this._people = this._people.concat(data.results);
          this._peopleSubject.next(this._people);
          if(data.next) this.loadPeople(data.next);
        })
}

Imidlertid mangler jeg erfaring med Rx.JS, og jeg er ganske sikker på at det finnes en bedre, renere måte å gjøre det på, ved å kjede Observables ved hjelp av en operator, men jeg kan ikke helt plassere det.

Noen ide om en operator jeg kan bruke? Takk!

Svar #1

Du kan bruke concatMap og concat-operatorene:

public loadPage( next:string ): Observable<string[]> {
    return this.http.get(next)
        .pipe(
          map( (response: Response) => response.json() )
          concatMap((data: any) => {
            if (data.next) {
              return Observable.of(data.results).concat(this.loadPage(data.next));
            }
            return Observable.of(data.results);
          })
        );
}

public loadPeople( next?:string ): void {
    if(!next) next = 'api/1.json';

    this.loadPage(next)
        .subscribe( (people: string[]) => {
            this._people = this._people.concat(people);
            this._peopleSubject.next(this._people);
        })
}

Du vil trenge følgende importeringer:

import { of } from 'rxjs'
import { concat, concatMap,  map } from 'rxjs/operators';

Svar #2

Du kan bruke Map og Subscribe eller MergeMap for det samme. Map og subscribe ville bli brukt som

this.http.get('/api/people/1')
  .map(res => res.json())
  .subscribe(character => {
    this.http.get(character.homeworld).subscribe(homeworld => {
      character.homeworld = homeworld;
      this.loadedCharacter = character;
    });
  });

}

Men på denne måten kan vi legge merke til to ting

  • Først begynner vi å se denne nestede pyramidestrukturen i innpakking av våre Observables, noe som ikke er veldig lesbart.

  • for det andre var våre to forespørsler sekvensielle

Så vi kan bruke mergemap for å mappe/iterere over Observable-verdiene som

this.homeworld = this.http.get('/api/people/1')
  .map(res => res.json())
  .mergeMap(character => this.http.get(character.homeworld))

}

Takk til **Cory Rylan** som har forklart dette vakkert enter link description here

Relaterte artikler