Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

296
Vistas
Rxjs - Chain http calls with Observables

I want to make 3 http calls which returns a boolean value. What I want is to make the next call only if the result of the previos call is true

IE:
call1() -> if false, stop, if true:
call2() -> if false, stop, if true:
call3()

now read results in a way that indicates which call returned false if so.

my first attemp with switchMap:

    this.call1()
      .pipe(
        switchMap((r1) => (r1 ? this.call2() : of(false))),
        switchMap((r2) => (r2 ? this.call3() : of(false)))
      )
      .subscribe((r) => {
        console.log('inside subscribe:', r);
      });

the problem here that now inside the subscribe I get:
'inside subscribe:' false
and I can't know if the false result is from call1,2 or 3.

so my solution is to save the results in external array, like so:

    // seriel execution with switchMap, we can use each result to the next call
    // + save all results
    const results = [false, false, false];
    this.call1()
      .pipe(
        // save stage1 result
        tap(r1 => results[0] = r1),
        // if true, make call2, else return false
        switchMap((r1) => (r1 ? this.call2() : of(false))),
        // save stage2 result
        tap(r2 => results[1] = r2),
        // if true, make call3, else return false
        switchMap((r2) => (r2 ? this.call3() : of(false))),
        // save stage3 result
        tap(r3 => results[2] = r3),
      )
      .subscribe((r) => {
        console.log('inside subscribe:', r); // r is the latest value results[2]
        console.log('all results:', results) // array of all stages [true,false,false]
      });

  }

and it seems to work, but maybe there is another way without external work? only with rxjs operators?

StackBlitz link:
https://stackblitz.com/edit/angular-rxjs-playground-zjnh7u?devtoolsheight=33&file=app/app.component.ts

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

Maybe something like this can work

this.call1()
  .pipe(
    switchMap((r1) => (r1 ? this.call2() : 
             of(false).pipe(tap(() => console.log('r1 returns false')),
    switchMap((r2) => (r2 ? this.call3() : 
             of(false).pipe(tap(() => console.log('r2 returns false'))),
    tap(respOfR3 => if(!respOfR3) {console.log('r3 returns false')})
  )
  .subscribe((r) => {
    console.log('inside subscribe:', r);
  });

At the same time consider that the sequence of booleans notified by your first Observable implicitly contains the info you are looking for. In fact the position of the first false you encounter reflects the first call that has returned false.

over 4 years ago · Santiago Trujillo Denunciar

0

I would attach the source to the outcome - simplest thing is a tuple [number, boolean], where the first element in the tuple/array is the source. A variation of the switchMap solution is:

    this.call1()
      .pipe(
        map((result) => [1, result]),
        switchMap((r1) => (r1[1] ? this.call2().pipe(map((result) => [2, result])) : of(r1))),
        switchMap((r2) => (r2[1] ? this.call3().pipe(map((result) => [3, result])) : of(r2)))
      )
      .subscribe((r) => {
        console.log('inside subscribe:', r);
      });

This has a pattern and is a bit verbose, we can do better:

    function attachSource(source: number, target: Observable<boolean>): Observable<[number, boolean]> {
      return target.pipe(map((result) => [source, result]));
    }

    attachSource(1, this.call1())
      .pipe(
        switchMap((r1) => (r1[1] ? attachSource(2, this.call2()) : of(r1))),
        switchMap((r2) => (r2[1] ? attachSource(3, this.call3()) : of(r2)))
      )
      .subscribe((r) => {
        console.log('inside subscribe (try2):', r);
      });

And if we generalize a little more, given the following:

    function attachSource<T>(source: number, target: () => Observable<T>): Observable<[number, T]> {
      return target().pipe(map((result) => [source, result]));
    }

    function series<T>(failed: (arg: T) => boolean, ...factories: (() => Observable<T>)[]): Observable<[number, T]> {
      return factories.reduce((agr, cur, index) => {
        if (index === 0) {
          return attachSource(index+1, cur);
        } else {
          return agr.pipe(switchMap((prevResult) => failed(prevResult[1]) ? of(prevResult) : attachSource(index+1, cur)));
        }
      }, empty<[number, T]>());
    }

It can be as simple as:

    series((x: boolean) => x, this.call1.bind(this), this.call2.bind(this), this.call3.bind(this))
      .subscribe((r) => {
        console.log('inside subscribe (try3):', r);
      });
over 4 years ago · Santiago Trujillo Denunciar

0

Here is a very clean solution using expand operator for recursive calls

const results = [false, false, false];
let count = 0;
this.call().pipe(
    tap(response => {
      results[count] = response
      count++
      }
    ),
    expand((response) => response && count < 3
               ? this.call()
               : EMPTY
    )
).subscribe((r) => {
    console.log('inside subscribe:', r); // r is the latest value results[2]
    console.log('all results:', results) // array of all stages [true,false,false]
});

And you don't really need multiple call function (call1, call2, call3), only one will be enough

call(): Observable<boolean> {
 let bool: boolean = this.randBool();
 return of(bool);
}

private randBool(): boolean {
  return Math.random() < 0.5
}

https://stackblitz.com/edit/angular-rxjs-playground-zvfpay?file=app/app.component.ts

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda