问题描述
我有一个UserProfileResolver
向UserProfileComponent
提供数据。我注意到我可以多次单击导航链接,发送大量HTTP请求。
是否有一种标准方法可以防止在初始请求完成之前发出后续请求?
nav
<li class="nav-item">
<a [routerLink]="['/user-profile/'+userId]" class="nav-link" routerLinkActive="active">
<i class="fa fa-user" aria-hidden="true"></i>
<ng-container i18n>Edit Profile</ng-container>
</a>
</li>
路由模块
const routes: Routes = [
{
path: ':id',component: UserProfileComponent,resolve: {data: UserProfileResolver},},];
解析器
export class UserProfileResolver {
constructor(private readonly userService: UserService,private readonly facilityService: FacilityService) {
}
public resolve(route: ActivatedRouteSnapshot,state: RouterStateSnapshot): Observable<any> {
return new Observable((observer) => {
forkJoin([
this.userService.getSingle(route.paramMap.get('id')),this.facilityService.getAll(),]).pipe(
map(([user,facilities]) => {
return {user,facilities};
}),catchError(() => of(undefined)),// dont resolve on error
tap(data => {
if (data !== undefined) {
observer.next(data);
} else {
observer.unsubscribe();
}
observer.complete();
}),).subscribe();
});
}
}
解决方法
您可以为Angular使用某些 Block UI 实现,例如ng-block-ui,可以将其配置为自动在httpRequests上启动,并防止用户在响应解析之前进行任何其他交互;
您可以通过以下命令进行安装:
npm install ng-block-ui --save
并按如下所示导入Angular应用程序:
// All other imports
import { BlockUIModule } from 'ng-block-ui';
@NgModule({
imports: [
BlockUIModule.forRoot()
],...
})
export class AppModule { }
这是Stackblitz上的一个简单示例。
,所以我最终只是禁用了按钮,直到导航解决
Nav
<li class="nav-item">
<a (click)="userProfileClick()" [class.disabled]="userProfileNavigating"
[routerLink]="['/user-profile/'+userId]" class="nav-link" routerLinkActive="active">
<i aria-hidden="true" class="fa fa-user"></i>
<ng-container i18n>Edit Profile</ng-container>
</a>
</li>
侧面导航
export class SideNavComponent {
public userId: string;
public userProfileNavigating: boolean;
constructor(public readonly authService: AuthService,private readonly router: Router,) {
this.userId = authService.userId;
// noticed i could click a router link a bunch of times before it resolved
router.events.pipe(filter(e => e instanceof NavigationEnd || e instanceof NavigationCancel)).subscribe(e => {
this.userProfileNavigating = false;
});
}
userProfileClick() {
if (this.router.routerState.snapshot.url !== `/user-profile/${this.userId}`) {
this.userProfileNavigating = true;
}
}
}
解析器
已针对Angular 10更新,这通过使用EMPTY
来取消解析器导航
export class UserProfileResolver implements Resolve<any> {
constructor(private readonly userService: UserService,private readonly facilityService: FacilityService) {
}
public resolve(route: ActivatedRouteSnapshot,state: RouterStateSnapshot):
Observable<{ user: User; facilities: Array<Facility> }> {
return forkJoin([
this.userService.getSingle(route.paramMap.get('id')),this.facilityService.getAll(),]).pipe(
map(([user,facilities]) => {
return {user,facilities};
}),catchError(() => EMPTY),);
}
}