【问题标题】:Cancel Route Resolve取消路由解析
【发布时间】:2018-04-30 18:35:36
【问题描述】:

我正在寻找一种方法来终止异步路由解析。

该场景是用户单击一个链接,该链接获取组件所需的数据,并且在解决该问题时用户回击或单击另一个链接。然后我想取消当前的解析并开始新的路由。

我无法通过侦听这些更改来拦截路由,因为在处理现有路由(仍处于解析阶段)时不会触发任何路由事件订阅。

例如,我的路由器可能如下所示:

const appRoutes: Routes = [
{
    path: 'resolvableRoute',
    component: ResolvableRouteComponent,
    resolve: {
      data: RouteResolver
    }
}];

以及解析器:

@Injectable()
export class RouteResolver implements Resolve<any> {

    constructor(private http: HttpClient) {}

    public resolve(router: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
        return this.http.get('api/path/for/data');
    }
}

在 http 调用以任何方式返回之前,路由器或多或少都卡住了。

我有一个很好的加载器,它在路由转换时启动,我不想在获得该组件所需的数据之前显示新组件,但我需要能够终止请求。

例如,如果我没有使用解析器,则用户可以在该组件获取数据时(例如在初始化时)离开该组件,因为我可以破坏该组件并终止 http 请求。以这种方式制作组件的缺点是我在处理获取数据时要么必须显示空白页面,要么显示不完整的页面。

【问题讨论】:

  • 你试过canDeactivate 路由的属性了吗?它可以用来终止请求。
  • CanDeactivate 仅在路由激活时有效。我需要在路由状态仍在触发时终止请求。基本上在 ResolveStart 和 ResolveEnd 之间。
  • 这个答案可能有用..stackoverflow.com/questions/36490926/…

标签: angular angular2-routing


【解决方案1】:

这对我来说效果很好(角度 7)

解析器

public resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
    return new Observable((observer) => {
      this.http.get().pipe(
        tap(data => {
          if (data !== undefined) {
            observer.next(data);
          }
          else {
            observer.unsubscribe();
          }
          observer.complete();
        })
      ).subscribe();
    });
  }

组件

public ngOnInit() {
    this.route.data.subscribe((parameters: { data: { objs: MyObjs[] } }) => {
      if (parameters.data) {
        this.dataSource = new MatTableDataSource(parameters.data.objs);
        this.dataSource.sort = this.sort;
      }
    });
  }

服务

  public get(): Observable<any> {
    return this.http.get<any>(`${environment.apiUrl}/api/get`).pipe(
      map((response: ApiResponse) => {
        return response.data    
      }),
      catchError(err => of(undefined))
    );
  }

【讨论】:

  • 你确定,Angular 8 是否支持这一点?
  • @Jony 我仍然在 Angular 10 中使用它。如果它解决了你的问题,请投票
【解决方案2】:

我现在将发布我的解决方案作为答案,因为这项工作可以满足我的需要,也许它也会对其他人有所帮助。

此解决方案的缺点是我需要路由器的包装器,而我不想这样做。

理想情况下,我可以创建对路由器导航队列的订阅,但所有这些方法/变量在 Angular 路由器中都是私有的,因此我无法访问它们。

相反,我创建了一个 RouterService,它允许我在新的导航事件触发时触发一个事件:

@Injectable()
export class RouterService {

    protected navigateListener = new EventEmitter<any>();

    constructor(private router: Router) {}

    public subscribe(generatorOrNext?: any, error?: any, complete?: any) {
        return this.navigateListener.subscribe(generatorOrNext, error, complete);
    }

    public navigate(commands: any[], extras?: NavigationExtras): Promise<boolean> {
        this.navigateListener.next();
        return this.router.navigate(commands, extras);
    }

    public navigateByUrl(url: string | UrlTree, extras?: NavigationExtras): Promise<boolean> {
        this.navigateListener.next();
        return this.router.navigateByUrl(url, extras);
    }

}

然后在我的 Resolve 内部,我创建了一个 observable(通常希望返回 http 请求),但同时也在监听 RouterService 上的事件变化。如果发出路由导航,那么我终止 http 请求,并让 promise 知道它可以完成......

public resolve(router: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<any> {
        return new Promise((resolve: any, reject: any) => {
                const subscription = this.http.get('/path/to/some/url').subscribe((data) => {
                    resolve(data)
                }, (error) => {
                    reject({
                        ngNavigationCancelingError: true
                    });
                });

                this.router.subscribe(change => {
                    subscription.unsubscribe();
                    reject({
                        ngNavigationCancelingError: true
                    });
                });
        });
    }

【讨论】:

    猜你喜欢
    • 2019-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-30
    • 1970-01-01
    • 1970-01-01
    • 2017-05-15
    相关资源
    最近更新 更多