Angular + ngrx: Async canActive Guard необходимо отменить где-то еще

Как видно из заголовка: есть ли способ сказать маршрутизатору отменить текущую навигацию?

Вот ситуация:

  • Маршрутный охранник отправляет действие.
  • Эффект выполняет асинхронный вызов на основе этого действия.
  • После завершения асинхронный вызов отправит действие обновления магазина для свойства.
  • Охранник подписан на селектор этого свойства (скажем, "свойство $")
  • Как только это свойство $ обновляется, охранник решает, разрешить навигацию или нет.

Этот подход работает только тогда, когда ресурс, запрошенный асинхронным действием эффекта, возвращается правильно (HTTP 200). Но в случае сбоя действия (скажем, HTTP 404) возникает проблема:

  • Охранник не одобрит и не отвергнет навигацию. Он находится в ожидании, и никакой другой запрос навигации не может быть выполнен, пока охранник не вернет true или false

Есть ли способ реализовать вызов, например, наивно говоря: this._router.cancelAllNavigationRequests()?

1 ответ

Вы не предоставили никакого кода, потому что ваше дело должно работать без необходимости cancelAllNavigationRequates, вы просто не обрабатывает ошибку HTTP должным образом. Вот метод, который я использовал в охране, он может помочь или дать вам идеи, похожий на тот, что был в примере с ngex: Этот охранник проверит, существует ли классификация уже и не является ли она частичной, перед тем, как позвонить в службу.

@Injectable()
export class ClassifiedGuardService implements CanActivate, CanActivateChild {
  constructor(private store: Store<fromRoot.State>, private classifiedService: ClassifiedService, private router: Router) {
  }

  vendorClassifiedAlreadyLoaded(id: string): Observable<boolean> {
    return this.store.pipe(
      select(fromContext.selectAllClassifieds),
      map(entities => {
        for (let i = 0; i < entities.length; i++) {
          if (entities[i].id === id && !entities[i].partial) {
            return true;
          }
        }
        return false;
      }),
      take(1)
    );
  }
  getVendorClassifiedFromServer(id: string) {
    return this.classifiedService.getVendorsClassified({id: id}).pipe(
      map(payload => new ClassifiedAction.GetVendorsClassifiedSuccess(payload)),
      tap((action: ClassifiedAction.GetVendorsClassifiedSuccess) => this.store.dispatch(action)),
      map(payload => !!payload),
      catchError(err => {
        this.store.dispatch(new ClassifiedAction.GetVendorsClassifiedFail(err));
        this.router.navigate(['/errors/bad-request']);
        return of(false);
      })
    );
  }


  getFullClassified(id: string): Observable<boolean> {
     return this.vendorClassifiedAlreadyLoaded(id).pipe(
        switchMap(inStore => {
          if (inStore) {
            return of(inStore);
          }
          return this.getVendorClassifiedFromServer(id);
        })
      );
  }

  canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
    return this.getFullClassified(route.params['id']);
  }

  canActivateChild(route: ActivatedRouteSnapshot) {
    return this.canActivate(route);
  }
}
Другие вопросы по тегам