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