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
|
||||
* rather than an error. */
|
||||
if (isNavigationCancelingError(e)) {
|
||||
this.navigated = true;
|
||||
const redirecting = isUrlTree(e.url);
|
||||
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);
|
||||
}
|
||||
const navCancel =
|
||||
|
|
|
@ -2256,11 +2256,18 @@ describe('Integration', () => {
|
|||
|
||||
describe('should redirect when guard returns UrlTree', () => {
|
||||
beforeEach(() => TestBed.configureTestingModule({
|
||||
providers: [{
|
||||
provide: 'returnUrlTree',
|
||||
useFactory: (router: Router) => () => { return router.parseUrl('/redirected'); },
|
||||
deps: [Router]
|
||||
}]
|
||||
providers: [
|
||||
{
|
||||
provide: 'returnUrlTree',
|
||||
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) => {
|
||||
|
@ -2305,6 +2312,49 @@ describe('Integration', () => {
|
|||
[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', () => {
|
||||
|
|
Loading…
Reference in New Issue