How to avoid RxJs subscribe callback hell?

Try something like:

import { map, switchMap } from 'rxjs/operators'

this.addressService.getById(this.data.id, this.data.userId).pipe(
  switchMap(address => this.dropdownService.getCidadesBrByEstado(address.name).pipe(
    // this pass both cities and address to the next observable in this chain
    map(cities => ({ cities, address }))
  ))
).subscribe(({ cities, address }) => {
  this.cities = cities
  this.address = address
})

Assuming, you don't actually care about streams you could also convert the Observables to promises in this case and use async/await:

async ngOnInit(): Promise<void> {
  this.address = await this.addressService.getById(this.data.id, this.data.userId).toPromise();
  this.cities = await this.dropdownService.getCidadesBrByEstado(this.address.name).toPromise();
}

And make sure you also catch the errors. try catch for example.


For angular when using RxJS, it suggests to use the Observable Class. To solve callback hell in the RxJS, You can use Observable' Operators api like switchMap() method(more methods for different scene are map(), concatMap(), ...). Here is my example about using the switchMap() method:
(1) Situation I met: I want to subsribe serviceC, but serviceC needs subsribe serviceB, and serviceB needs subsribe serviceA

const serviceA(params): Observable<any>;
const serviceB(params): Observable<any>;
const serviceC(params): Observable<any>;

serviceA(paramsA).subscribe(
    serviceAResult => {
        serviceB(paramsB).subscribe(
            serviceBResult => {
                serviceC(params).subscribe(
                    serviceCResult => {
                        // here is my logic code. Oh, Shit subscribe hell!
                    }
                )
            }
        )
    }
)

(2) Use switchMap() method to optimize code structure

const serviceB$ = serviceA(paramsA).pipe(
    switchMap(serviceAResult => {
        return serviceB(paramsB);
    })
);

const serviceC$ = serviceB$.pipe(
    switchMap(serviceBResult => {
        return serviceC(paramsC);
    })
);

serviceC$.subscribe(
    serviceCResult => {
        // here is my logic code.
    },
    error =>{
        // handle error
    }
);

Good post about dealing with callback hell.