Как ждать и получать ответ на каждый вызов службы HttpClient из цикла в Angular 4 - PullRequest
0 голосов
/ 29 августа 2018

У меня есть ситуация, когда мне нужно запустить цикл и получить соответствующие элементы ' description . Затем вместе с идентификаторами предметов и другой информацией я должен включить извлеченное описание в таблицу данных.

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

Тело функции:

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
}

В componentService Сервис:

construcutor(private httpConn: HttpClient){}

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

Проблема :

Поскольку он работает в цикле, а подписка является асинхронным вызовом, то после запуска цикла в forEach он выходит. В результате описание не назначается переменной (ITEM_DEF) в интерфейсе.

Чтобы решить эту проблему, я внес небольшое изменение в использование promise. В сервис добавила:

 import 'rxjs/add/operator/toPromise';

И обновил метод обслуживания как:

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

Также изменено в компоненте: Внутри fetchDescription функция:

заменено .subscribe как .then

Но проблема все еще сохраняется. Пожалуйста, дайте мне знать, где я делаю неправильно, чтобы реализовать эту логику.

Ответы [ 3 ]

0 голосов
/ 29 августа 2018

Решение:

Тело функции:

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

Звоните:

this.fetchDescription(element).subscribe((description: string) => {
   ITEM_ID : element.id,
   ITEM_DEF : description
});
0 голосов
/ 12 сентября 2018

Для этого вы должны использовать 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));
}

Здесь оператор concatMap будет запускать следующую наблюдаемую только в том случае, если первая завершена, т.е. доступен ответ на первый вызов API. Каждый раз, когда вы вызываете метод complete() для субъекта триггера $ , он завершает наблюдаемые и вызовы API. Возможно, вам придется изменить логику вызова complete().

0 голосов
/ 29 августа 2018

решение состоит в том, чтобы преобразовать наблюдаемое в обещание, но не используя его!

Пример:

Это ваша сервисная функция, которая отправляет запрос:

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

Это функция для отправки всех запросов в классе компонента:

 async sendAll() {
    let response = [];
    for(let i = 0; i < 5; i++) {
        response[i] = await this.myService.myRequest();
    }
  // Got all the results!
 }
...