javascriptangulartypescriptangular-resolver

Make Angular resolver wait for images


What can I do to make resolver wait until it gets images from the API. Right now, Angular waits until data is received, shows page and then tries to get images of the post.

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

Solution

  • Try:

    @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([]);
            }
          })
        );
      }
    }
    

    That should get you started. The issue with your approach is that you're subscribing in the inner observable and I don't think the route resolver is waiting for it.