Search code examples
angulartypescriptrxjsobservable

How to avoid RxJs subscribe callback hell?


I'm using Angular RxJs subscribe to make a HttpClient call and then make another call using the values from the first one. In this case, there's a call to get address object, and then i make a call using this object. Like this:

@Injectable()
export class AddressService {
  constructor(private http: HttpClient) { }

  getById(addressId: string, userId: string) {
    return this.http.get(BACKEND_URL + 'getAddressById/' + [addressId, userId]);
  }
}
  
export class AddressModalComponent implements OnInit {
  constructor(private alertService: AlertService, private addressService: AddressService,           @Inject(MAT_DIALOG_DATA) public data: any, private dropdownService: DropdownService)

  ngOnInit() {
    this.addressService.getById(this.data.id, this.data.userId)
        .subscribe(
          (address: Address) => {
            this.dropdownService.getCidadesBrByEstado(address.name)
              .subscribe((cities: BrCity[]) => {
                this.cities = cities;
                this.address = address;
              },
              error => console.log(error));
          }, error => { this.alertService.error(error);
          }
        );
    }
  }
}

I'm trying to avoid multiple Subscribes, there is many like this in my code. I need an Async/Await approach like Node.js promises, but using Observables at component level. I'm not very familiar with RxJs commands... is there a better way to make many calls with just one subscribe and catch?


Solution

  • 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
    })