问题
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