0

I have four subscribes that dependable on each other. I know there are too many answers regarding avoiding nested subscribe. But nobody answers more than two levels.

how to avoid that many nested subscribe

this is my component code

if (this.code) {

    this.appService.updateData('Users/clever_token', {code: this.code}).subscribe(data => {

        if (data.detail) {

            this.accessToken = data.detail.access_token;

            this.appService.getCleverData('/v2.1/me', this.accessToken).subscribe(data1 => {

                if (data1.links) {

                    this.userData.user_type = data1.type;

                    this.appService.getCleverData(data1.links[1].uri, this.accessToken).subscribe(data2 => {

                        if (data2.data) {

                            this.userData.name = data2.data.name.first + ' ' + data2.data.name.last;

                            this.userData.clever_id = data2.data.id;

                            this.userData.email = data2.data.email;

                            this.appService.updateData('Users/cleaver_login', this.userData).subscribe(data3 => {

                                if (data3.detail) {

                                    console.log(data3.detail);
                                }
                            });
                        }
                    });
                }
            });
        }
    });
}

this is service code

getCleverData(url, token) {

    let reqHeader = new HttpHeaders({
        'Authorization': 'Bearer ' + token
    })

    return this.http.get(API_PREFIX + url, { headers: reqHeader })
        .pipe(
            map((data: any) => {
                console.log(data);

                if (data) return data;
            }),
            catchError(this.handleError)
        );
}

/** PUT: update a data to the server */
updateData (url, data?) {

    let httpParams = new HttpParams();
    Object.keys(data).forEach(function (key) {
         httpParams = httpParams.append(key, data[key]);
    });

    return this.http.post(this.apiUrl + url, httpParams, httpOptions)
    .pipe(
        map((data: any) => {
            if (data.status == 0) {
                this.presentToast(data.message);
            }

            if (data) return data;
        }),
        catchError(this.handleError)
    );
}

is there any way to avoid that many subscribe. I can't remove any of it because its some of it from our server and others are third party

anonymous
  • 13
  • 1
  • 3
  • look at rxjs operators (mergeMap, zip, forkJoin) – enno.void Apr 17 '19 at 11:50
  • Take a look to forkJoin: https://stackoverflow.com/questions/43166214/merging-http-observables-using-forkjoin/43166302, this example has just 2 http requests, but you can add more requests. – Federico Galfione Apr 17 '19 at 11:55
  • I tried. but there is an example of only two levels and I can't use forkJoin because of all API requests dependent one another. I can't call them together – anonymous Apr 17 '19 at 11:56
  • So you need flatMap: https://stackoverflow.com/questions/44593900/rxjs-one-observable-feeding-into-another. Obviously you have to change your data before send them, but at least you have no nested observer – Federico Galfione Apr 17 '19 at 12:00
  • You wouldn't nest subscribe, also not for one level – baao Apr 17 '19 at 12:02
  • Check tis out: https://stackoverflow.com/a/55701271/5955138 – rcanpahali Apr 17 '19 at 13:19

1 Answers1

1

There are a few options but as I see you need that structure because you need data from the previous observable so you can use filter() and switchMap().

filter() is able to filter out values which do not contain necessary values switchMap() - to switch to a new stream.

UPDATE:

There is a refactored version of your code:

if (!this.code) {
  return;
}

this.appService.updateData('Users/clever_token', {code: this.code}).pipe(
  filter(data => !!data.detail),
  switchMap(data => {
    this.accessToken = data.detail.access_token;

    return this.appService.getCleverData('/v2.1/me', this.accessToken);
  }),
  filter(data1 => !!data1.links),
  switchMap(data1 => {
    this.userData.user_type = data1.type;

    return this.appService.getCleverData(data1.links[1].uri, this.accessToken);
  }),
  filter(data2 => !!data2.data),
  switchMap(data1 => {
    this.userData.name = data2.data.name.first + ' ' + data2.data.name.last;
    this.userData.clever_id = data2.data.id;
    this.userData.email = data2.data.email;

    return this.appService.updateData('Users/cleaver_login', this.userData);
  }),
).subscribe(data3 => {
  if (data3.detail) {
    console.log(data3.detail);
  }
}
Maxim Palenov
  • 650
  • 7
  • 17