1

i have a problem during use httpclient in angular7 Route guards service. since i have to get a result from a background server to judge if pass or not. but httpclient service is async,so the variable canPass is always false,how to deal with the problem? any opinion will be appreciated. here is my code:

judgePass(route: string): Observable<CommonResult> {
const url = `${this.baseUrl}/check`;
const formData = new FormData();
formData.append('url', route);
return this.httpClient.post<CommonResult>(url, formData, {});
}

canPass: boolean = false;

canActivate(route: ActivatedRouteSnapshot, state: 
    RouterStateSnapshot):boolean {
    this.authService.judgePass(state.url).subscribe(res => {
        let code = res['code'];
        if (code == 0) {
            this.canPass = true;
        } else {
            this.message.create('error', res.message);
            this.canPass = false;
        }
    });
    return this.canPass;
}
SixSixSix
  • 25
  • 7
  • just return `this.canPass` inside the `if else` block – mast3rd3mon Nov 29 '18 at 09:41
  • thx,but the function canActivate must have a boolean variable to return – SixSixSix Nov 29 '18 at 09:49
  • Nope, it won't work as the subscription will be executed after the main function has returned. You can't return from inside a subscription! It would defeat the advantages of having subscriptions. – Qortex Nov 29 '18 at 09:57

1 Answers1

3

Your code does not work because you don't wait for the return value, and immediately return this.canPass, while its value is not yet assigned.

As you can see in the Angular docs, you perfectly can return an observable.

Just return the observable instead, as in:

canActivate(route: ActivatedRouteSnapshot, state: 
    RouterStateSnapshot): Observable<boolean> {
    return this.authService.judgePass(state.url).pipe(map(res => {
        let code = res['code'];
        if (code == 0) {
            return true;
        } else {
            this.message.create('error', res.message);
            return false;
        }
    }));
}

The pipe / map stuff is just to jump in the observable and change the result to true/false.

There are other ways, among which using async/await as in this SO post, although I prefer the above solution.

Qortex
  • 7,087
  • 3
  • 42
  • 59
  • so where do you propose the OP subscribes to the `judgePass` function? without the subscribe, the call wont execute – mast3rd3mon Nov 29 '18 at 10:01
  • No need, the Angular framework does it on its own. – Qortex Nov 29 '18 at 10:09
  • Other example: https://stackoverflow.com/questions/50717424/implementing-canactivate-auth-guard-in-angular?rq=1 – Qortex Nov 29 '18 at 10:11
  • Actually, it's a duplicate, I'll flag it. – Qortex Nov 29 '18 at 10:11
  • it doesnt and never has (not sure on angularjs but thats different anyway). that is the whole point to the subscribe function. without it, it just declares the http call but it only executes once it has been subscribed to – mast3rd3mon Nov 29 '18 at 10:11
  • This answer is correct, not sure why it's downvoted... – DDRamone Nov 29 '18 at 10:28
  • This is the correct answer. – Chrillewoodz Nov 29 '18 at 10:30
  • Strong recommend to use catchError in pipe. If some error will be on url request/response, then it fail with Uncaught (in promise): HttpErrorResponse error. Example to catch it: .pipe(catchError(err => { console.error(err); return of(false); }), map(res => { ... – tapin13 Apr 19 '22 at 08:28