Angular 4 - routerLinks without starting slash get rewritten after uncaught error

别来无恙 提交于 2019-12-12 16:18:35

问题


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?


回答1:


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



来源:https://stackoverflow.com/questions/43889889/angular-4-routerlinks-without-starting-slash-get-rewritten-after-uncaught-erro

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!