取消路线解决

时间:2017-11-17 03:44:13

标签: angular angular2-routing

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

该方案是用户单击获取组件所需数据的链接,同时解析用户点击或点击其他链接。然后我想取消当前的解决方案并开始新的路由。

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

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

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呼叫以任何方式返回,路由器或多或少地卡住了。

我有一个很好的加载器,在路由转换时启动,我不希望显示新组件,直到我有该组件所需的数据,但我需要能够终止请求。 / p>

例如,如果我没有使用解析器,则用户可以在组件获取数据时离开组件(例如在init上),因为我可以随后破坏组件并终止http请求。以这种方式执行组件的缺点是,我在处理提取数据时必须显示空白页面或不完整的页面。

2 个答案:

答案 0 :(得分:0)

我现在要发布我的解决方案作为答案,因为这项工作做了我需要它,也许它也会帮助其他人。

这个解决方案的缺点是我需要路由器的包装器,我宁愿不需要它。

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

相反,我创建了一个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请求,让承诺知道它可以完成......

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

答案 1 :(得分:0)

这对我来说很好(角度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))
    );
  }