Заставьте преобразователь Angular ждать изображений

Что я могу сделать, чтобы преобразователь ждал, пока он не получит изображения из API. Прямо сейчас Angular ждет, пока не будут получены данные, показывает страницу, а затем пытается получить изображения публикации.

@Injectable()
export class DataResolverService implements Resolve<any> {
  constructor(
    private router: Router,
    private API: ApiService
  ) {}

  resolve(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<any> | Observable<never> {
    return this.API.getPostById(route.params.id).pipe(
      map(response => {
        if (response["images"]) {
          const images = [];
          response["images"].forEach(image => {
            this.API.getImageById(image.id).subscribe(
              (img: any) => {
                const imageObject = {
                  url: window.URL.createObjectURL(img),
                };
                images.push(imageObject);
              }
            );
          });
          response["images"] = images;
          return response;
        }

        return response;
      })
    );
  }
}

person ShabbyAbby    schedule 05.03.2020    source источник
comment
Похоже, вы встроили Observable; поэтому преобразователь разрешается после разрешения первого. Я подозреваю, что вы хотите вернуть внутреннюю наблюдаемую, а не внешнюю наблюдаемую. Об этом должен позаботиться оператор rxjs. Возможно MergeMap?   -  person JeffryHouser    schedule 05.03.2020
comment
Ты прав. SwitchMap помог мне решить проблему.   -  person ShabbyAbby    schedule 05.03.2020


Ответы (2)


Пытаться:

@Injectable()
export class DataResolverService implements Resolve<any> {
  constructor(
    private router: Router,
    private API: ApiService
  ) {}

  resolve(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<any> | Observable<never> {
    return this.API.getPostById(route.params.id).pipe(
      switchMap(response => { // change this into a switchMap
        if (response["images"]) {
          return combineLatest(
            // combine all of the request for the images
            ...response["images"].map(image => this.API.getImageById(image.id)),
          ).pipe(
            map(images => images.map(image => ({ url: window.URL.createObjectURL(image) })),
            map(images => ({ response: images })), // This map may be unnecessary
          );
        } else {
         return of([]);
        }
      })
    );
  }
}

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

person AliF50    schedule 05.03.2020
comment
Оно работало завораживающе. Спасибо за помощь. Последняя карта помогла мне добавить изображения к ответу. - person ShabbyAbby; 05.03.2020

Вы возвращаете «ответ» до разрешения вашего асинхронного метода «this.API.getImageById (image.id)». Перед возвратом необходимо дождаться завершения всех асинхронных итераций. Есть несколько вариантов сделать это, это вариант:

return this.API.getPostById(route.params.id).pipe(
      map(async response => {
        if (response["images"]) {
          const images = [];
          response["images"].forEach(image => {
           await this.API.getImageById(image.id).then(
              (img: any) => {
                const imageObject = {
                  url: window.URL.createObjectURL(img),
                };
                images.push(imageObject);
              }
            );
          });
          response["images"] = images;
          return response;
        }

        return response;
      })
    );
person Matheus Carvalho    schedule 05.03.2020