fix(router): location changes and redirects break the back button (#10742)
This commit is contained in:
parent
203b2ba637
commit
04c6b2fe85
|
@ -77,6 +77,7 @@ export class SpyLocation implements Location {
|
|||
|
||||
var url = path + (query.length > 0 ? ('?' + query) : '');
|
||||
this.urlChanges.push(url);
|
||||
this._subject.emit({'url': url, 'pop': false});
|
||||
}
|
||||
|
||||
replaceState(path: string, query: string = '') {
|
||||
|
|
|
@ -47,6 +47,7 @@ export interface NavigationExtras {
|
|||
preserveQueryParams?: boolean;
|
||||
preserveFragment?: boolean;
|
||||
skipLocationChange?: boolean;
|
||||
replaceUrl?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -160,7 +161,7 @@ export class Router {
|
|||
*/
|
||||
initialNavigation(): void {
|
||||
this.setUpLocationChangeListener();
|
||||
this.navigateByUrl(this.location.path(true));
|
||||
this.navigateByUrl(this.location.path(true), {replaceUrl: true});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -336,7 +337,8 @@ export class Router {
|
|||
private scheduleNavigation(url: UrlTree, extras: NavigationExtras): Promise<boolean> {
|
||||
const id = ++this.navigationId;
|
||||
this.routerEvents.next(new NavigationStart(id, this.serializeUrl(url)));
|
||||
return Promise.resolve().then((_) => this.runNavigate(url, extras.skipLocationChange, id));
|
||||
return Promise.resolve().then(
|
||||
(_) => this.runNavigate(url, extras.skipLocationChange, extras.replaceUrl, id));
|
||||
}
|
||||
|
||||
private setUpLocationChangeListener(): void {
|
||||
|
@ -347,12 +349,14 @@ export class Router {
|
|||
// we fire multiple events for a single URL change
|
||||
// we should navigate only once
|
||||
return this.currentUrlTree.toString() !== tree.toString() ?
|
||||
this.scheduleNavigation(tree, change['pop']) :
|
||||
this.scheduleNavigation(tree, {skipLocationChange: change['pop'], replaceUrl: true}) :
|
||||
null;
|
||||
}));
|
||||
}
|
||||
|
||||
private runNavigate(url: UrlTree, preventPushState: boolean, id: number): Promise<boolean> {
|
||||
private runNavigate(
|
||||
url: UrlTree, shouldPreventPushState: boolean, shouldReplaceUrl: boolean,
|
||||
id: number): Promise<boolean> {
|
||||
if (id !== this.navigationId) {
|
||||
this.location.go(this.urlSerializer.serialize(this.currentUrlTree));
|
||||
this.routerEvents.next(new NavigationCancel(id, this.serializeUrl(url)));
|
||||
|
@ -415,9 +419,9 @@ export class Router {
|
|||
|
||||
new ActivateRoutes(state, storedState).activate(this.outletMap);
|
||||
|
||||
if (!preventPushState) {
|
||||
if (!shouldPreventPushState) {
|
||||
let path = this.urlSerializer.serialize(appliedUrl);
|
||||
if (this.location.isCurrentPathEqualTo(path)) {
|
||||
if (this.location.isCurrentPathEqualTo(path) || shouldReplaceUrl) {
|
||||
this.location.replaceState(path);
|
||||
} else {
|
||||
this.location.go(path);
|
||||
|
|
|
@ -872,6 +872,44 @@ describe('Integration', () => {
|
|||
|
||||
expect(location.path()).toEqual('/team/22');
|
||||
})));
|
||||
|
||||
it('should not break the back button when trigger by location change',
|
||||
fakeAsync(inject(
|
||||
[Router, TestComponentBuilder, Location],
|
||||
(router: Router, tcb: TestComponentBuilder, location: Location) => {
|
||||
const fixture = tcb.createFakeAsync(RootCmp);
|
||||
advance(fixture);
|
||||
router.resetConfig([
|
||||
{path: 'initial', component: BlankCmp},
|
||||
{path: 'old/team/:id', redirectTo: 'team/:id'},
|
||||
{path: 'team/:id', component: TeamCmp}
|
||||
]);
|
||||
|
||||
location.go('initial');
|
||||
location.go('old/team/22');
|
||||
|
||||
// initial navigation
|
||||
router.initialNavigation();
|
||||
advance(fixture);
|
||||
expect(location.path()).toEqual('/team/22');
|
||||
|
||||
location.back();
|
||||
advance(fixture);
|
||||
expect(location.path()).toEqual('/initial');
|
||||
|
||||
// location change
|
||||
(<any>location).go('/old/team/33');
|
||||
|
||||
|
||||
advance(fixture);
|
||||
expect(location.path()).toEqual('/team/33');
|
||||
|
||||
location.back();
|
||||
advance(fixture);
|
||||
expect(location.path()).toEqual('/initial');
|
||||
})));
|
||||
|
||||
// should not break the back button when trigger by initial navigation
|
||||
});
|
||||
|
||||
describe('guards', () => {
|
||||
|
|
|
@ -108,6 +108,7 @@ export interface NavigationExtras {
|
|||
preserveQueryParams?: boolean;
|
||||
queryParams?: Params;
|
||||
relativeTo?: ActivatedRoute;
|
||||
replaceUrl?: boolean;
|
||||
skipLocationChange?: boolean;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue