2

I have a situation where I need to run a loop and fetch respective items' description. Then along with the item Ids and other information I have to include the fetched description in a datatable.

addDescription(){
this.arrayOfItems.forEach(element => {

   // CALL a function which will make a service call
   this.fetchDescription(element);

   //CODE TO DECLARE AN INTERFACE TO ASSIGN RESPECTIVE VALUES. eg.

   // ITEM_ID : element.id,
   // ITEM_DEF : this.fetchedDescription.join("\n")
}

Function body:

fetchDescription(elementToFetchDesc){

 //Declaring HTTPPARAMS in PassingParams variable

 this.componentService.getDesc(PassingParams)
         .subscribe((response: HttpResponse<any>) => {
                if(response.status ==200){
                    this.fetchedDescription = reponse.body.output.slice(6,-1);
                }
                //Code if response status is NOT 200
}

In componentService Service:

construcutor(private httpConn: HttpClient){}

getDesc(Params){
    // Declare URL
    return this.httpConn.get(URL, {params: Params, observe: 'response'});
}

The problem:

As it's running in a loop and the subscription is an async call, so, after running the loop in forEach it's coming out. As a result the description is not getting assigned to the variable (ITEM_DEF) in the interface.

To solve this issue I implemented a little change to use promise. In service I added:

 import 'rxjs/add/operator/toPromise';

And updated the service method as:

 return this.httpConn.get(URL, {params: Params, observe: 'response'})
                     .toPromise();    // converted observable into promise

Also changed in component: Inside fetchDescription function:

replaced .subscribe as .then

But the issue still persists. Please let me know where I'm doing wrong to implement this logic.

2
  • 1
    This may help you: quora.com/… Commented Aug 29, 2018 at 6:45
  • @SamCodes: Have you found any solution for it? As I am also facing the same issue. Commented Nov 23, 2018 at 11:22

3 Answers 3

2

the solution is to convert observable to promise but not using then!

Example:

This is your service function that sends the request:

myRequest(num) {
   return this.http.get('http://someUrl.com/' + num).toPromise(); 
}

This is the function to send all requests in a component class:

 async sendAll() {
    let response = [];
    for(let i = 0; i < 5; i++) {
        response[i] = await this.myService.myRequest();
    }
  // Got all the results!
 }
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for correcting me. I'd like to use this data in response. So I have used a global var this.description = response; after the loop completion. The calling function of sendAll() will use the values. But I faced the issue: even the response is not filled with all the data it tries to execute those next line of codes. So, how to make it wait until the all the records are fetched.
After the loop, you should have all the data in response. If you are not sure, put a console.log in the loop (before request) and put another one after the loop it shows you when and which code is executed.
1

Solution:

Function Body:

fetchDescription(elementToFetchDesc):  Observable<string> {

  //Declaring HTTPPARAMS in PassingParams variable

  return this.componentService.getDesc(PassingParams)
      .map((response: HttpResponse<any>) => {
          if(response.status ==200){
             return reponse.body.output.slice(6,-1);
          }
       });
     }
  }

Call:

this.fetchDescription(element).subscribe((description: string) => {
   ITEM_ID : element.id,
   ITEM_DEF : description
});

2 Comments

I have tried this before posting this question, but not working.
I have forgot to add return in fetchDescription method. Could you please try it agin ?
0

For this you should use rxjs.

checkStatus(url: string, id: string): Observable<string> {
const trigger$ = new Subject<string>();
const time = Date.now();

return trigger$.asObservable().startWith(url).concatMap((u) => {
  return this.ping(u).map(() => {
    trigger$.complete();

    return id;
  }).catch((err) => {
      trigger$.next(u);

    return Observable.empty<any>();
  });
});
}


protected ping(url: string): Observable<any> {
return this.http.get(url)
  .catch(err => Observable.throw(err));
}

Here the concatMap operator will fire the next observable only if the first one is complete i.e the response of first API call is available. Whenever you call the method complete() on the trigger$ subject it will complete the observable and the API calls. You might have to change the logic of calling complete().

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.