简体   繁体   中英

how to wait for the subscribe to finish before going back to caller method in angular

Following is the code flow for the particular scenario. First, a POST call. This POST call updates a table's column in database. Then, subscribe to it, and make a GET call. Using the result of this GET call, I update a parameter on the page. After both these calls are done, I should make an PUT call to update some variables(which not getting retrieved from the previous GET call), and then emit an event. Below is the code:

save({ job, status }) {
    this.apiService.serviceMethod(job, status);
    console.log('calls after publishTaskAction');
    this.apiService.updatePutMethod(job).subscribe(() => {
      console.log('after updateTask');
    });
    this.notify.emit('saved!');
  }

ApiService methods:

serviceMethod(job: Model, status: string) {
    if (status) {
      let observ = of() as Observable<void>;
      if (status === 'Publish') {
        observ = this.firstPostMethod(task);
      }
      if (status === 'UnPublish') {
        observ = this.firstPostMethod(task);
      }
      console.log('calls before observ');
      observ.subscribe(() => {
        console.log('inside observ');
        this.firstGETCall(task).subscribe();
        console.log('after observ');
      });
    }
  }

What I am trying to achieve is that serviceMethod should complete the execution(complete both the Post and Get call), and then go back to the caller method and execute updatePutMethod. What is happening is that the execution is returning to the caller and updatePutMethod is executed and then observ.subscribe is called. Due to this, at backend the result is not as expected. This the order in which console.logs are executed:

calls before observ
calls after publishTaskAction
before updateTask http call
inside observ
after observ
tafter updateTask

I followed this solution: subscribe getting called after below codes execution? . and updated my code as below:

save({ job, status }) {
    this.apiService. serviceMethod(job, status).subscribe(
          (data) => {
            this.apiService.firstPostMethod(job).subscribe(
              (data) => {
                this.taskApiService.updateTask(task).subscribe();
              }
            );
            this.notify.emit('saved!');
          });
}

But this is wrong. Also, I read from few sources that a subscribe shouldn't be called from another subscribe block. So please help with any suggestion.

This is where pipe for RxJS is handy. You can continue one observable after another before calling the final subscribe.

To reiterate your desired functionality: Within your UI component you press the Save button which takes a job and status. You want to POST the job to save a task to the database, then do a GET to retrieve additional data.

Note, before continuing on, if you are POSTing to save TASK and the following GET is to retrieve the updated TASK, you can always return the updated TASK from the POST call.

Once you get the updated data, you update UI which then updates an additional variable that you then need to update using the PUT call.

Finally, once all variables have been POSTed, GETted, PUTted and the UI updated, you want to emit to the parent component all the operations are complete.

My recommendation.

save(job: Model, status: string) {
    console.log('Starting apiService.serviceMethod');
    this.apiService.serviceMethod(job, status).pipe(
        switchMap((job: Model) => {
            if (job) {
                // Some update of job is require here since the GET call doesn't know 
                // whereas the UI does. 
                // Modify job variable here.
            
                console.log('Starting PUT call');
                return this.apiService.updatePutMethod(job); 
            } else {
                console.log('Skipping PUT call');
                return of(null);
            }
        })
    ).subscribe(() => {
        console.log("Ready to emit");
        this.notify.emit('Saved!');
    });
}


import { of } from 'rxjs';

serviceMethod(job: Model, status: string): Observable<Model> {
    if (status && (status === 'Publish' || status === 'UnPublish')) {
        console.log('Staring POST call');
        return this.firstPostMethod(task).pipe(
            switchMap((task) => {
                console.log('Starting GET call');               
                return this.firstGETCall(task);
            })
        );
    } else {
        // either status is null/empty or does not equal either of the strings.
        return of(null);
    }
}

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