fix(router): restore 'history.state' object for navigations coming from Angular router (#28108) (#28176)

When navigations coming from Angular router we may have a payload stored in state property. When this
 exists, set extras's state to the payload.

PR Close #28176
This commit is contained in:
Alexander Vologin 2019-01-16 04:09:03 -05:00 committed by Andrew Kushnir
parent 3d156162af
commit df76a2048b
2 changed files with 62 additions and 1 deletions

View File

@ -920,7 +920,15 @@ export class Router {
// hybrid apps. // hybrid apps.
setTimeout(() => { setTimeout(() => {
const {source, state, urlTree} = currentChange; const {source, state, urlTree} = currentChange;
this.scheduleNavigation(urlTree, source, state, {replaceUrl: true}); const extras: NavigationExtras = {replaceUrl: true};
if (state) {
const stateCopy = {...state};
delete stateCopy.navigationId;
if (Object.keys(stateCopy).length !== 0) {
extras.state = stateCopy;
}
}
this.scheduleNavigation(urlTree, source, state, extras);
}, 0); }, 0);
} }
this.lastLocationChangeInfo = currentChange; this.lastLocationChangeInfo = currentChange;

View File

@ -159,6 +159,59 @@ describe('Integration', () => {
expect(navigation.extras.state).toEqual({foo: 'bar'}); expect(navigation.extras.state).toEqual({foo: 'bar'});
}))); })));
it('should set history.state when navigation with browser back and forward',
fakeAsync(inject([Router, Location], (router: Router, location: SpyLocation) => {
router.resetConfig([
{path: '', component: SimpleCmp},
{path: 'simple', component: SimpleCmp},
]);
const fixture = createRoot(router, RootCmp);
let navigation: Navigation = null!;
router.events.subscribe(e => {
if (e instanceof NavigationStart) {
navigation = <Navigation>router.getCurrentNavigation()!;
}
});
const state = {foo: 'bar'};
router.navigateByUrl('/simple', {state});
tick();
location.back();
tick();
location.forward();
tick();
expect(navigation.extras.state).toBeDefined();
expect(navigation.extras.state).toEqual(state);
})));
it('should not error if state is not {[key: string]: any}',
fakeAsync(inject([Router, Location], (router: Router, location: SpyLocation) => {
router.resetConfig([
{path: '', component: SimpleCmp},
{path: 'simple', component: SimpleCmp},
]);
const fixture = createRoot(router, RootCmp);
let navigation: Navigation = null!;
router.events.subscribe(e => {
if (e instanceof NavigationStart) {
navigation = <Navigation>router.getCurrentNavigation()!;
}
});
location.replaceState('', '', 42);
router.navigateByUrl('/simple');
tick();
location.back();
advance(fixture);
// Angular does not support restoring state to the primitive.
expect(navigation.extras.state).toEqual(undefined);
expect(location.getState()).toEqual({navigationId: 3});
})));
it('should not pollute browser history when replaceUrl is set to true', it('should not pollute browser history when replaceUrl is set to true',
fakeAsync(inject([Router, Location], (router: Router, location: SpyLocation) => { fakeAsync(inject([Router, Location], (router: Router, location: SpyLocation) => {
router.resetConfig([ router.resetConfig([