简体   繁体   中英

Angular/rxJs concatMap - making two web api (http) calls, either dont finish and control move to subsequent lines

I am trying to utilize rxJs concatMap inside my angular 9 application. Basically I need to make two web api calls using http, both return observables, populate other values. The first call need to return some values, which will be used as parameter for second api call and then supposed to continue. I tried to utilize the concatMap for this using tap, but no luck. When the method(checkForRenewal()) is called, the first line gets hit, but waiting for completion of api call or go to second api call, it moves to other lines.

The program is either not waiting for the first to finish and second call don't execute correctly and the control move to next lines (after 2 web api calls). After few seconds, I see the first API is triggered and the values are read, but it is too late.

I have other api calls following the contactMap...but excluding from this post.

How to achieve this or what is wrong? Do i need a final subscribe after concatMap? Sample code below.

 checkForRenewal(): void {

 this.ls.getSoftwareModules()  //first web api call
        .pipe(         
            tap((data) => {                  
                {
                    try {
                        const dataXml = data.filter((data) => data.SoftwareModuleName == 'Activation')[0].XmlConfig;
                        if (dataXml) {
                            const config = xmlToJson(dataXml);
                            this.autoRenewalEnabled =
                                config['configuration'].appSettings.param.filter(
                                    (data) => data.name == 'AutoRenewalEnabled',
                                )[0].value === 'true';


                            this.autoRenewalCheckingFrequencyInHours = config[
                                'configuration'
                            ].appSettings.param.filter(
                                (data) => data.name === 'AutoRenewalCheckingFrequencyInHours',   //this line not hitting first, but later gets hit
                            )[0].value;

                        }
                    } catch (e) {

                    }
                }
            }),
            concatMap(() => this.ls.checkForRenewalAlreadyRan(this.autoRenewalCheckingFrequencyInHours, true)),  //2nd web api call
            tap((data2) => {
                this.skipKeyRenewal = data2;
                console.log('checkForRenewalAlreadyRan-->' + data2);
            }),
        )
        .subscribe((resp) => {
            console.log(resp);
        });

    if (this.skipKeyRenewal) {   //issue ...control seem to reach here first before making the above  api calls using concatMap
        console.log('auto renewal program already ran in last 24 hours, so processing will not resume!');
        return;
    } else {
        console.log('process continue for auto renewal...');
    }



 this._activationService.getActivationSites().subscribe({
        next: (resp) => {
            this.sites = resp;
            this.siteName = this.sites[0].SiteName;
            this.siteID = this.sites[0].SiteID;
        },
        error: (err) => {
            console.log(`err-->${err}`);
        },
    });

    this._activationService.getUuidPartial().subscribe({
        next: (resp) => {
            this.hardwareID = resp;
            this.decimalHardwareID = parseInt(this.hardwareID, 16);
        },
        error: (err) => {
            console.log(`err-->${err}`);
        },
    });

    hData = this._activationService.getProductActivations('ProductA', this.showKeys);   
    gData = this._activationService.getProductActivations('ProductB', this.showKeys);

    //other stuff goes here on wards


    ==============================================

    //two api calls returning observables in service ( lookup.service.ts)

//1st web api   
getSoftwareModules(where: string = '', orderBy: string = ''): Observable<SoftwareModule[]> {
    const url = `${this.config.host}${GLOBAL.SV_GET_MODULE_LIST}sessionID=${this.appSession.session.SessionID}&where=${where}&orderby=${orderBy}`;
    return this.http.get<SoftwareModule[]>(url);
}


//2nd web api 
checkForRenewalAlreadyRan(frequencyInHoures: number, isApiReady: boolean): Observable<boolean> {
    const url = `${this.config.host}${GLOBAL.SV_GET_KEY_RENEWAL_SETTINGS}sessionID=${this.appSession.session.SessionID}&frequencyInHoures=${frequencyInHoures}&isApiReady=${isApiReady}`;       
     return this.http.get<boolean>(url);      
}

I see three member variables this.autoRenewalEnabled , this.autoRenewalCheckingFrequencyInHours , and this.skipKeyRenewal being assigned values inside the asynchronous calls. These variables are assigned values asynchronously. So when you try to access it outside the subscription, they may not be assigned the values yet. The issue can be seen in trying to access this.skipKeyRenewal outside the subscription. It should actually be inside the subscription

this.ls.getSoftwareModules()
  .pipe(
    ...
  )
  .subscribe((resp) => {
    console.log(resp);
    if (this.skipKeyRenewal) {   //issue ...control seem to reach here first before making the above  api calls using concatMap
      console.log('auto renewal program already ran in last 24 hours, so processing will not resume!');
      return;
    } else {
      console.log('process continue for auto renewal...');
    }
  });

Likewise all the code that depend on any of these three variables must be inside the subscription.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM