简体   繁体   English

Angular - 如何使 canActivate 等待 promise 响应?

[英]Angular - How to make canActivate to await for promise response?

I try to check in CanActivate gurad if user is logged in.如果用户已登录,我会尝试签入 CanActivate gurad。
If yes, then I navigate him to some page.如果是,那么我将他导航到某个页面。
If not, then I navigate him to login page.如果没有,那么我将他导航到登录页面。
I use promise.我使用 promise。

I have a service named LoginService :我有一个名为LoginService的服务:

export class LoginService {

  urlcheck = 'http://localhost:80/isconnected.php';
  resultCheck;

  constructor(private http: HttpClient, private router: Router)
  {
  }

  async checkLogin()
  {
    const x = await this.updateConnectedState();
    return x;
  }

  updateConnectedState()
  {
    //formData here...
    return this.http.post(this.urlcheck, formData).toPromise()
      .then(
        (response) =>
        {
          this.resultCheck = response; 
          console.log(response);
          return this.resultCheck.state; //state is true/false
        },
        (error) => 
        { 
            console.log(error); 
            return false;  
        }
      );
    }
  }


the canActivate Gurad: canActivate Gurad:

export class BackHomeGuardService implements CanActivate
{
  constructor(private logService: LoginService, private router: Router)
  {
  }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean>|boolean
  {
    const result = this.logService.checkLogin();
    console.log( result);

    if (result)
    {
      console.log('true');
      // navigate to hom page
      return true;
    }
    else
    {
      console.log('false');
      // navigate to login page
      return false;
    }
  }
}

The guard canActivate function always return true.守卫可以激活 function 总是返回 true。
I checked in console and the the promise result is:我检查了控制台,promise 结果是:

__zone_symbol__state: null
__zone_symbol__value: []

I want to make the canActive await for result before it will do something.我想让 canActive 在它做某事之前等待结果。
What if my backend (php code file) will take 30 seconds to be completed?如果我的后端(php 代码文件)需要 30 秒才能完成怎么办?
I need a solution.我需要一个解决方案。 Thanks.谢谢。

According to CanActivate 's type:根据CanActivate的类型:

export declare interface CanActivate {
    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree;
}

the method canActivate can return Observable, Promise or boolean.方法canActivate可以返回 Observable,Promise 或 boolean。

You can simply return your checkLogin() call like:您可以简单地返回您的checkLogin()调用,例如:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean>|boolean {
    return this.logService.checkLogin();
}

and everything will work.一切都会奏效。


UPDATE更新

answering the question "how do I handle the returned boolean in my canActivate" from comments从评论中回答问题“我如何处理我的 canActivate 中返回的 boolean”

The idea of the CanActivate is to restrict the access to some routes due to a certain condition. CanActivate 的想法是由于某种条件限制对某些路由的访问。 You can perform some side-effects (but I'm not sure how they will be displayed, unless it's a console.log) by chaining your Promise or Observable:可以通过链接 Promise 或 Observable 来执行一些副作用(但我不确定它们将如何显示,除非它是 console.log):

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean>|boolean {
    return this.logService
      .checkLogin()
      .then(canLogin => {
         console.log('Can user login:', canLogin);
         // perform you side effects here
      })

}

If you look at the return type of the canActivate method:如果查看 canActivate 方法的返回类型:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree

} }

It can return a simple boolean or a Promise, or an Observable.它可以返回一个简单的 boolean 或 Promise 或 Observable。 Also, I don't think you need to convert the Observable to a Promise inside your LoginService.另外,我认为您不需要在 LoginService 中将 Observable 转换为 Promise。

canActivate can work with observable so you can map query result to return observable in this way canActivate 可以与 observable 一起使用,因此您可以 map 查询结果以这种方式返回 observable

import { of, Observable } from 'rxjs';
import { catchError, map } from 'rxjs/operators';

export class LoginService {

  urlcheck = 'http://localhost:80/isconnected.php';
  resultCheck;

  constructor(private http: HttpClient, private router: Router) {
  }

  checkLogin(): Observable<boolean> {

    //formData here...
    return this.http.post(this.urlcheck, formData).pipe(
      map(
        (response) => {
          this.resultCheck = response;
          console.log(response);
          return this.resultCheck.state; //state is true/false
        }),
        catchError(error => {
          console.log(error);
          return of(false);
        })
      );
  }
}

export class BackHomeGuardService implements CanActivate
{
  constructor(private logService: LoginService, private router: Router)
  {
  }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean>
  {
    return this.logService.checkLogin();
  }
}

canActivate can have the following return type: boolean , Promise<boolean> , or Observable<boolean> . canActivate可以具有以下返回类型: booleanPromise<boolean>Observable<boolean>

Since you already have checkLogin() to return a Promise that will resolve to true/false .由于您已经有checkLogin()返回一个Promise ,它将解析为true/false Let's stick with Promise or Observable .让我们坚持使用PromiseObservable As the others have already answered, you can absolutely just return this.logService.checkLogin()正如其他人已经回答的那样,您绝对可以返回this.logService.checkLogin()

   canActivate(): Promise<boolean> {
      return this.logService.checkLogin();
   }

Now, I see that you want to navigate somewhere else based on the checkLogin() value as well.现在,我看到您还想根据checkLogin()值导航到其他地方。 And I'd suggest to convert the Promise to Observable so you can leverage tap operator.我建议将Promise转换为Observable ,以便您可以利用tap运算符。 You can do it like the following:你可以这样做:

   return fromPromise(this.logService.checkLogin()).pipe(
      tap(isLogin => {
         if (!isLogin) {
            // not login. navigate to login page
         }
      })
   )

We do not really want to navigate somewhere on true because when it's true, the Guard will navigate the user to the route that is being guarded.我们真的不想在true的某个地方导航,因为当它为 true 时,Guard 会将用户导航到被保护的路线。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM