fix(router): redirect to root url when returned as UrlTree from guard (#28271)
When a UrlTree of root url was returned by a guard as a redirection, the navigation was not processed. The issue came from the error handler which incorrectly marked the router as already navigated. Fixes #27845 PR Close #28271
This commit is contained in:
parent
3de06dd794
commit
50732e1564
@ -715,9 +715,14 @@ export class Router {
|
|||||||
/* This error type is issued during Redirect, and is handled as a cancellation
|
/* This error type is issued during Redirect, and is handled as a cancellation
|
||||||
* rather than an error. */
|
* rather than an error. */
|
||||||
if (isNavigationCancelingError(e)) {
|
if (isNavigationCancelingError(e)) {
|
||||||
this.navigated = true;
|
|
||||||
const redirecting = isUrlTree(e.url);
|
const redirecting = isUrlTree(e.url);
|
||||||
if (!redirecting) {
|
if (!redirecting) {
|
||||||
|
// Set property only if we're not redirecting. If we landed on a page and
|
||||||
|
// redirect to `/` route, the new navigation is going to see the `/` isn't
|
||||||
|
// a change from the default currentUrlTree and won't navigate. This is
|
||||||
|
// only applicable with initial navigation, so setting `navigated` only when
|
||||||
|
// not redirecting resolves this scenario.
|
||||||
|
this.navigated = true;
|
||||||
this.resetStateAndUrl(t.currentRouterState, t.currentUrlTree, t.rawUrl);
|
this.resetStateAndUrl(t.currentRouterState, t.currentUrlTree, t.rawUrl);
|
||||||
}
|
}
|
||||||
const navCancel =
|
const navCancel =
|
||||||
|
@ -2256,11 +2256,18 @@ describe('Integration', () => {
|
|||||||
|
|
||||||
describe('should redirect when guard returns UrlTree', () => {
|
describe('should redirect when guard returns UrlTree', () => {
|
||||||
beforeEach(() => TestBed.configureTestingModule({
|
beforeEach(() => TestBed.configureTestingModule({
|
||||||
providers: [{
|
providers: [
|
||||||
provide: 'returnUrlTree',
|
{
|
||||||
useFactory: (router: Router) => () => { return router.parseUrl('/redirected'); },
|
provide: 'returnUrlTree',
|
||||||
deps: [Router]
|
useFactory: (router: Router) => () => { return router.parseUrl('/redirected'); },
|
||||||
}]
|
deps: [Router]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: 'returnRootUrlTree',
|
||||||
|
useFactory: (router: Router) => () => { return router.parseUrl('/'); },
|
||||||
|
deps: [Router]
|
||||||
|
}
|
||||||
|
]
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('works', fakeAsync(inject([Router, Location], (router: Router, location: Location) => {
|
it('works', fakeAsync(inject([Router, Location], (router: Router, location: Location) => {
|
||||||
@ -2305,6 +2312,49 @@ describe('Integration', () => {
|
|||||||
[NavigationEnd, '/redirected'],
|
[NavigationEnd, '/redirected'],
|
||||||
]);
|
]);
|
||||||
})));
|
})));
|
||||||
|
|
||||||
|
it('works with root url',
|
||||||
|
fakeAsync(inject([Router, Location], (router: Router, location: Location) => {
|
||||||
|
const recordedEvents: any[] = [];
|
||||||
|
let cancelEvent: NavigationCancel = null !;
|
||||||
|
router.events.forEach((e: any) => {
|
||||||
|
recordedEvents.push(e);
|
||||||
|
if (e instanceof NavigationCancel) cancelEvent = e;
|
||||||
|
});
|
||||||
|
router.resetConfig([
|
||||||
|
{path: '', component: SimpleCmp},
|
||||||
|
{path: 'one', component: RouteCmp, canActivate: ['returnRootUrlTree']}
|
||||||
|
]);
|
||||||
|
|
||||||
|
const fixture = TestBed.createComponent(RootCmp);
|
||||||
|
router.navigateByUrl('/one');
|
||||||
|
|
||||||
|
advance(fixture);
|
||||||
|
|
||||||
|
expect(location.path()).toEqual('/');
|
||||||
|
expect(fixture.nativeElement).toHaveText('simple');
|
||||||
|
expect(cancelEvent && cancelEvent.reason)
|
||||||
|
.toBe('NavigationCancelingError: Redirecting to "/"');
|
||||||
|
expectEvents(recordedEvents, [
|
||||||
|
[NavigationStart, '/one'],
|
||||||
|
[RoutesRecognized, '/one'],
|
||||||
|
[GuardsCheckStart, '/one'],
|
||||||
|
[ChildActivationStart, undefined],
|
||||||
|
[ActivationStart, undefined],
|
||||||
|
[NavigationCancel, '/one'],
|
||||||
|
[NavigationStart, '/'],
|
||||||
|
[RoutesRecognized, '/'],
|
||||||
|
[GuardsCheckStart, '/'],
|
||||||
|
[ChildActivationStart, undefined],
|
||||||
|
[ActivationStart, undefined],
|
||||||
|
[GuardsCheckEnd, '/'],
|
||||||
|
[ResolveStart, '/'],
|
||||||
|
[ResolveEnd, '/'],
|
||||||
|
[ActivationEnd, undefined],
|
||||||
|
[ChildActivationEnd, undefined],
|
||||||
|
[NavigationEnd, '/'],
|
||||||
|
]);
|
||||||
|
})));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('runGuardsAndResolvers', () => {
|
describe('runGuardsAndResolvers', () => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user