Skip to content

Commit

Permalink
fix(router): restore 'history.state' object for navigations coming fr…
Browse files Browse the repository at this point in the history
…om 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
  • Loading branch information
alecvolo authored and AndrewKushnir committed Aug 11, 2020
1 parent 3d15616 commit df76a20
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 1 deletion.
10 changes: 9 additions & 1 deletion packages/router/src/router.ts
Expand Up @@ -920,7 +920,15 @@ export class Router {
// hybrid apps.
setTimeout(() => {
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);
}
this.lastLocationChangeInfo = currentChange;
Expand Down
53 changes: 53 additions & 0 deletions packages/router/test/integration.spec.ts
Expand Up @@ -159,6 +159,59 @@ describe('Integration', () => {
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',
fakeAsync(inject([Router, Location], (router: Router, location: SpyLocation) => {
router.resetConfig([
Expand Down

0 comments on commit df76a20

Please sign in to comment.