Angular - Как заставить canActivate ждать ответа на обещание? - PullRequest
1 голос
/ 23 апреля 2020

Я пытаюсь проверить в CanActivate gurad, если пользователь вошел в систему. Если да, то я перехожу к нему на какую-то страницу. Если нет, то я перехожу к нему на страницу входа. Я использую обещание.

У меня есть служба с именем 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;  
        }
      );
    }
  }

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

Функция защиты canActivate всегда возвращает true. Я проверил в консоли, и результат обещания:

__zone_symbol__state: null
__zone_symbol__value: []

Я хочу, чтобы canActive ждал результата, прежде чем он что-то сделает. Что если мой бэкэнд (файл кода php) займет 30 секунд? Мне нужно решение. Спасибо.

Ответы [ 4 ]

1 голос
/ 23 апреля 2020

В соответствии с типом CanActivate:

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

метод canActivate может возвращать Observable, Promise или Boolean.

Вы можете просто вернуть свой checkLogin() вызов как :

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

и все будет работать.


ОБНОВЛЕНИЕ

, отвечая на вопрос "как мне обращаться с возвращенными логическое в моем canActivate " из комментариев

Идея CanActivate состоит в том, чтобы ограничить доступ к некоторым маршрутам из-за определенного условия. Вы можете выполнить некоторые побочные эффекты (но я не уверен, как они будут отображаться, если это не console.log), приковав цепью ваш Promise или Observable:

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

}
0 голосов
/ 23 апреля 2020

canActivate может иметь следующий тип возврата: boolean, Promise<boolean> или Observable<boolean>.

Так как у вас уже есть checkLogin() для возврата Promise, которое разрешится до true/false. Давайте придерживаться Promise или Observable. Как уже отвечали другие, вы можете просто вернуть this.logService.checkLogin()

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

Теперь я вижу, что вы хотите перейти куда-нибудь еще, основываясь на значении checkLogin(). И я бы посоветовал преобразовать Promise в Observable, чтобы вы могли использовать оператора tap. Вы можете сделать это следующим образом:

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

На самом деле мы не хотим ориентироваться где-то на true, потому что когда это правда, Guard направит пользователя к охраняемому маршруту.

0 голосов
/ 23 апреля 2020

canActivate может работать с наблюдаемыми, так что вы можете отобразить результат запроса, чтобы вернуть наблюдаемый таким образом

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();
  }
}
0 голосов
/ 23 апреля 2020

Если вы посмотрите на тип возврата метода canActivate:

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

}

Он может возвращать простое логическое значение, или Обещание, или Observable. Кроме того, я не думаю, что вам нужно конвертировать Observable в Promise внутри вашего LoginService.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...