1

I have 2 http calls, where the second depends on the first. How do I approach making a canActivate guard that waits for the two http calls to finish before returning true, and if it takes "too long", say 5 seconds, it returns false. In searching around it seems maybe rxjs.timeout could work but I'm not getting how to wire that up in the context of the 2 http calls.

My current guardless code is like this. I'm expecting(?) that the guard would eliminate the code in the component ngOnInit().

export class ApiQueryService {
  constructor(private http: HttpClient) { }

  getFirstObj$(name: string): Observable<any> {
    return this.http.get(environment.apiUrl + '?name=' + name);
  }

  // "link" parameter comes from the getFirstObj$ call
  getSecondObj$(link: string): Observable<any> {
    return this.http.get(link);
  }
}

export class InitService {
  constructor(private  apiQueryService: ApiQueryService) {
  }

  init(name: string) {
    this.apiQueryService.getFirstObj$(name)
      .subscribe(firstObj => {
      this.apiQueryService.getSecondObj$(firstObj.link))
          .subscribe(secondObj => {
            console.log('secondObj:', secondObj);
          });
      });
  }
}

export class MyComponent implements OnInit {
  ngOnInit() {
    this.initService.init('myName');
  }
}
eflat
  • 919
  • 3
  • 13
  • 34

1 Answers1

3

You can indeed use timeout, and switchMap to chain the two calls.

return this.apiQueryService.getFirstObj$(name).pipe(
  switchMap(firstObj => this.apiQueryService.getSecondObj$(firstObj.link)),
  map(secondObj => true),
  timeout(5000),
  catchError(() => of(false))
);
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Thanks, it works! It'll be a bit before I grok these well enough to imagine how to chain these together myself. One more question on extending this. I want to save firstObj and secondObj into a service/singleton because there are other properties I'll need later. Where in this code can I add like "this.configStoreService.firstObj = firstObj;"? – eflat Dec 18 '19 at 22:10
  • Aha, I figured it out. I made "firstObj.link" into "this.handleFirstObj(firstObj)", and I made "secondObj => true" into "secondObj => this.handleSecondObj(secondObj)". Those 'handle*' functions can then do the extra work and return as needed. – eflat Dec 18 '19 at 22:56