правильный синтаксис с использованием rx js наблюдаемых, вспомогательных функций и обещаний - PullRequest
1 голос
/ 22 апреля 2020

Я не могу правильно написать код.

Пока что я:

  getTender(id: number): Observable<TenderResponse> {

    const tender$ = this.get<TenderResponse>('/tenders/' + id);
    const images$ = tender$.pipe(mergeMap((tender: TenderResponse): Observable<TenderResponse> => {
        return combineLatest(
          tender.locations.loading.map(
            (location: TenderLocation, index: number) => {
              location.not_uploaded_images = from(this.fileService.getCargoImagesAtLocation(location.id));

              return location;
            }
          )
        )
      }
    );

    return images$;
  }

Идея, что метод должен получить объект (тендер). Когда это загружено - у него есть список местоположений, у каждого местоположения есть идентификатор. Используя эти идентификаторы (для определения местоположения) - я должен получить список изображений. А затем вернуть результат - Тендер с указанием местоположения с изображениями.

В настоящее время этот код не работает из-за несовместимых типов и устареваний

this.fileService.getCargoImagesAtLocation is обещание, поэтому я использую оператор rx js from для преобразования его в наблюдаемый ..

Результат метода getTender должен иметь тип Observable .

ОБНОВЛЕННЫЙ КОД:

  getImages(locationId: number): Observable<NotUploadedImage[]> {
    return from(this.fileService.getCargoImagesAtLocation(locationId));
  }

  getTender(id: number): Observable<TenderResponse> {
    return this.get<TenderResponse>('/tenders/' + id).pipe(
      mergeMap(
        (tender: TenderResponse): Observable<TenderResponse> => {
          tender.locations.loading.forEach((location: TenderLocation) => {
            location.not_uploaded_images = this.getImages(location.id);
          });
          return of(tender);
        }
      )
    );
  }

Проблема в том, что not_uploaded_images не разрешается, а свойство возвращаемого объекта Tender имеет тип Observable , но это должен быть тип NotUploadedImages[].

Я думаю, это потому, что оператор combineLatest не используется. Но как только я его использую - я не могу правильно настроить код.

ЗАКЛЮЧИТЕЛЬНЫЙ РЕЗУЛЬТАТ РАБОТЫ:



  getImages(locationId: number): Observable<NotUploadedImage[]> {
    return from(this.fileService.getCargoImagesAtLocation(locationId));
  }

  getTender(id: number): Observable<TenderResponse> {
    return this.get<TenderResponse>('/tenders/' + id).pipe(
      mergeMap((tender: TenderResponse) =>
        combineLatest(
          tender.locations.loading.map((location: TenderLocation) =>
            this.getImages(location.id)
          )
        ).pipe(
          map((images: NotUploadedImage[][]) => {
            return tender.locations.loading.map(
              (location: TenderLocation, index: number): TenderLocation => {
                return {
                  ...location,
                  not_uploaded_images: images[index],
                };
              }
            );
          }),
          map((locations: TenderLocation[]) => {
            tender.locations.loading = locations;
            return tender;
          })
        )
      )
    );
  }

1 Ответ

1 голос
/ 22 апреля 2020

Ты рядом, но location.not_uploaded_images = from... и return location; не складываются. Вы не возвращаете Observable.

Возможно, это то, что вы хотите (и немного более кратко):

return combineLatest(
    tender.locations.loading.map((location: TenderLocation) => 
        from(this.fileService.getCargoImagesAtLocation(location.id))
    )
)

Редактировать

Чтобы ответить на ваши комментарии. Если я правильно понимаю, mergeMap принимает ваш родительский объект в качестве входных данных и подписывается на новый Observable. Этот новый Observable имеет две цели: получить изображения; верните их вместе с родительским объектом. Для этого мы можем создать второй канал и карту в контексте функции mergeMap.

На основе вашей ссылки на stackblitz это должно работать:

getTender(id: number): Observable<TenderResponse> {
    return this.serviceThatGetsTender(id)
        .pipe(
            mergeMap((tender: TenderResponse) =>
                combineLatest(
                  tender.locations.loading.map((location: TenderLocation) => this.getImages(location.id))
                )
                .pipe(
                  map(images => tender.locations.loading.map(
                    (t, i) => ({ ...t, not_uploaded_images: images[i] } as TenderLocation)
                  )),
                  map(locations => {
                    tender.locations.loading = locations;
                    return tender
                  })
                )
            )
        )
}

Обратите внимание на возвращаемый объект: Observable<{tender: TenderResponse, images: NotUploadedImage}>. Это только потому, что я не знаю всех полей в ваших объектах, я предполагаю, что вы хотите поместить изображения в объект TenderResponse.

Также, что касается вашего предупреждения: убедитесь, что вы импортируете правильные combineLatest. Один под 'rxjs' и один под 'rxjs/operators'. Вам нужен первый.

...