Angular 4 - 没有启动斜杠的routerLinks在未被捕获的错误后被重写 [英] Angular 4 - routerLinks without starting slash get rewritten after uncaught error

查看:131
本文介绍了Angular 4 - 没有启动斜杠的routerLinks在未被捕获的错误后被重写的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是 Angular 4 + zonejs:路由在未捕获的错误后停止工作
,因为我们有一个很难将建议的更改整合到我们的项目中。



这个原因可以在这个改编的plunker中看到 https://embed.plnkr.co/oUE71KJEk0f1emUuMBp8/



routerLinks in我们的项目没有斜杠/前缀。
一旦您在访问错误组件后导航到另一个部分,这将打破整个导航。
所有链接都是用当前路径重写的,例如:回家路线链接属性中的斜杠修复了这种行为。



为什么会这样?



是否有关于此的文档/规范?



我们只发现了这个角票对于RouterLink指令的api


或者不以斜杠开头,路由器会查找当前激活路径的子节点。


但这与上一个问题中建议的解决方法分别与未被捕获的错误有什么关系?

解决方案

发生导航错误后,恢复路由状态

  this.currentRouterState = storedState; 
this.currentUrlTree = storedUrl;

https://github.com/angular/angular/blob/4.1.2/packages/router/src/router.ts #L750-L751



在执行 createUrlTree 之后,获得了startPosition:

  function findStartingPosition(nav,tree,route){
if(nav.isAbsolute){//它将在你使用时执行routeLink
中的`/`返回新位置(tree.root,true,0);
}
if(route.snapshot._lastPathIndex === -1){//没有'/'
返回新位置(route.snapshot._urlSegment,true,0);
}
...
}

我们可以看到在上面的代码中,当您在routeLinks中使用斜杠时,路由器将根据 tree.root 创建未经更改的位置。



然后它用于在下面的代码中创建 UrlTree oldSegmentGroup

 函数树(oldSegmentGroup,newSegmentGroup,urlTree,queryParams,fragment){
...
if(urlTree.root === oldSegmentGroup) {//在错误
返回新的UrlTree(newSegmentGroup,qp,fragment)之后将为false;
}
返回新的UrlTree(replaceSegment(urlTree.root,oldSegmentGroup,newSegmentGroup),qp,fragment);
}

所以解决方法可能如下:



我们不再需要 RouteReuseStrategy



我们存储错误状态

  let erroredUrlTree; 
let erroredState;

export class AppModule {
constructor(private router:Router){
router.events.subscribe(function(e){
if(e instanceof NavigationError){
erroredState =(router as any).currentRouterState;
erroredUrlTree =(router as any).currentUrlTree;
}
});
}
}

并在发生错误后恢复:

  @Injectable()
导出类MyErrorHandler实现ErrorHandler {
构造函数(private inj:Injector){}

handleError(错误:任何):void {
console.log('MyErrorHandler:'+ error);
if(erroredUrlTree){
let router:any = this.inj.get(Router);
router.currentRouterState = erroredState;
router.currentUrlTree = erroredUrlTree;
erroredState = null;
erroredUrlTree = null;
}
}
}

改良的Plunker



看起来很糟糕但也许它有助于理解问题是什么


This is a follow up to Angular 4 + zonejs: routing stops working after uncaught error since we had a hard time integration the suggested changes into our project.

The reason for this can be seen in this adapted plunker https://embed.plnkr.co/oUE71KJEk0f1emUuMBp8/ in app.html:

The routerLinks in our project were not prefixed with a slash "/". This breaks the whole navigation once you navigate to another section after visiting the "Error Component". All links are being rewritten with the current path, e.g. home.

Adding the slash in the routerLink attributes fixes this behaviour.

Why is that?

And is there some documentation/spec concerning this?

We only found this angular ticket and the api for RouterLink-directive which says

or doesn't begin with a slash, the router will instead look in the children of the current activated route.

But how is this related to what is happening with an uncaught error respectively with the suggested workaround from the previous question?

解决方案

After an navigation error happens the routing state is restored

this.currentRouterState = storedState;
this.currentUrlTree = storedUrl;

https://github.com/angular/angular/blob/4.1.2/packages/router/src/router.ts#L750-L751

After that within executing createUrlTree the startPosition is obtained:

function findStartingPosition(nav, tree, route) {
    if (nav.isAbsolute) { // it will be executed when you use `/` in routeLink
        return new Position(tree.root, true, 0);
    }
    if (route.snapshot._lastPathIndex === -1) { // without '/'
        return new Position(route.snapshot._urlSegment, true, 0);
    }
    ...
}

As we can see in code above when you use slash in routeLinks then router will create position based on tree.root which has not changed.

then it is used for creating UrlTree (oldSegmentGroup in code below)

function tree(oldSegmentGroup, newSegmentGroup, urlTree, queryParams, fragment) {
    ...
    if (urlTree.root === oldSegmentGroup) { // will be false after the error
        return new UrlTree(newSegmentGroup, qp, fragment);
    }
    return new UrlTree(replaceSegment(urlTree.root, oldSegmentGroup, newSegmentGroup), qp, fragment);
}

So workaround might be as follows:

We no longer need RouteReuseStrategy.

We store errored state

let erroredUrlTree;
let erroredState;

export class AppModule {
  constructor(private router: Router) {
    router.events.subscribe(function (e) {
      if(e instanceof  NavigationError ) {
        erroredState = (router as any).currentRouterState;
        erroredUrlTree =  (router as any).currentUrlTree;
      }
    });
  }
}

and recovery it after error occurs:

@Injectable()
export class MyErrorHandler implements ErrorHandler {
  constructor(private inj: Injector) {}

  handleError(error: any): void {
    console.log('MyErrorHandler: ' + error);
    if(erroredUrlTree) {
      let router: any = this.inj.get(Router);
      router.currentRouterState = erroredState;
      router.currentUrlTree = erroredUrlTree;
      erroredState = null;
      erroredUrlTree = null;
    }
  }
}

Modified Plunker

It looks terrible but maybe it will help to understand what the problem is

这篇关于Angular 4 - 没有启动斜杠的routerLinks在未被捕获的错误后被重写的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆