angular - Angular2: Nästlade observabler i Guard


Jag har en Guard som skyddar en viss rutt. I canActive-metoden behöver jag göra två http-förfrågningar, där den andra triggas baserat på svaret från den första. Den andra förfrågningen görs dock aldrig och jag antar att det handlar om den nästlade konstruktionen av att returnera Observables.

1 canActivate(route: ActivatedRouteSnapshot,
2          state: RouterStateSnapshot) : Observable<boolean>|boolean {
3  return this.provider.getA().map(
4    dataA => {
5      return this.provider.getB().map(
6        dataB => {
7          return (dataB.allowed);
8        }
9      );
     }
   );  
 }

Både getA() och getB() returnerar följande:

getA() : Observable<any> {
  return this.http.post(URL,payload).
                   map(response => response.json());

};

Koden är förenklad, men du kan anta att getA() och getB() fungerar korrekt. getA() skickas korrekt över nätverket när Guard anropas, getB() skickas däremot aldrig. Debuggern avslutas tyst på rad 5.

En sak till, TypeScript visar en varning som förmodligen redan berättar lösningen för mig, men jag är för mycket en nybörjare med Observables särskilt för att veta vad jag ska göra med det:

Observable<Observable<boolean>>' is not assignable 
to type 'Observable<boolean>'

För att gissa löser sig aldrig konstruktionen av Observables, det är därför det inte finns någon varning och jag väntar tills tidens slut. Min naiva uppfattning var att, så länge någon Observable returnerar ett booleanvärde (som görs i rad 7), skulle abonnenten veta hur man hanterar det.

Jag är glad att läsa dina tips. Dags att gå till sängs...

Svar #1

Du bör använda switchMap här:

return this.provider.getA().switchMap(
  dataA => {
    return this.provider.getB().map(
      dataB => {
        return (dataB.allowed);
      }
    );
  }
);

I din kod skapar du ett Observable av Observables. switchMap planar ut den strukturen och skickar vidare de emitterade objekten från B genom A.

Svar #2

Uppdatering för lösningen som delades av @j2l4e

De flesta av RxJS-operatörerna är nu rörbara, så utan pipe() kommer det att orsaka ett fel/varning.

lösning med pipe()

  canActivate(): boolean | Observable<boolean> | Observable<Observable<boolean>> {
    return this.httpClient
      .get('https://jsonplaceholder.typicode.com/todos')
      .pipe(
        switchMap((dataA: any) => {
          console.log('dataA :: ', dataA);
          return this.httpClient
            .get('https://jsonplaceholder.typicode.com/posts')
            .pipe(
              map((dataB: any) => {
                // add your logic here...
                console.log('data b', dataB);
                return false;
              })
            );
        })
      );
  }

För mer information hänvisa till de officiella dokumenten:

  1. https://rxjs.dev/guide/operators
  2. https://rxjs.dev/api/index/function/pipe
  3. https://rxjs.dev/api/operators/switchMap