From 71d0eeb966843d372068bf69489da278ff7969fb Mon Sep 17 00:00:00 2001 From: Jason Aden Date: Thu, 7 Feb 2019 16:13:30 -0800 Subject: [PATCH] feat(router): add hash-based navigation option to setUpLocationSync (#28609) The `setUpLocationSync` function in @angular/router/upgrade didn't previously let you sync hash-based navigations. With this change, you can now pass an option to `setUpLocationSync` that will make sure location changes run in Angular in hash-based apps. Fixes #24429 #21995 PR Close #28609 --- packages/router/upgrade/src/upgrade.ts | 13 ++++++++-- packages/router/upgrade/test/upgrade.spec.ts | 25 ++++++++++++++++++++ tools/public_api_guard/router/upgrade.d.ts | 2 +- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/packages/router/upgrade/src/upgrade.ts b/packages/router/upgrade/src/upgrade.ts index ae0cd19750..e6fd41c888 100644 --- a/packages/router/upgrade/src/upgrade.ts +++ b/packages/router/upgrade/src/upgrade.ts @@ -58,7 +58,7 @@ export function locationSyncBootstrapListener(ngUpgrade: UpgradeModule) { * * @publicApi */ -export function setUpLocationSync(ngUpgrade: UpgradeModule) { +export function setUpLocationSync(ngUpgrade: UpgradeModule, urlType: 'path' | 'hash' = 'path') { if (!ngUpgrade.$injector) { throw new Error(` RouterUpgradeInitializer can be used only after UpgradeModule.bootstrap has been called. @@ -71,7 +71,16 @@ export function setUpLocationSync(ngUpgrade: UpgradeModule) { ngUpgrade.$injector.get('$rootScope') .$on('$locationChangeStart', (_: any, next: string, __: string) => { - const url = resolveUrl(next); + let url; + if (urlType === 'path') { + url = resolveUrl(next); + } else if (urlType === 'hash') { + // Remove the first hash from the URL + const hashIdx = next.indexOf('#'); + url = resolveUrl(next.substring(0, hashIdx) + next.substring(hashIdx + 1)); + } else { + throw 'Invalid URLType passed to setUpLocationSync: ' + urlType; + } const path = location.normalize(url.pathname); router.navigateByUrl(path + url.search + url.hash); }); diff --git a/packages/router/upgrade/test/upgrade.spec.ts b/packages/router/upgrade/test/upgrade.spec.ts index abbb7cb9a8..03a8c5a265 100644 --- a/packages/router/upgrade/test/upgrade.spec.ts +++ b/packages/router/upgrade/test/upgrade.spec.ts @@ -79,6 +79,30 @@ describe('setUpLocationSync', () => { expect(RouterMock.navigateByUrl).toHaveBeenCalledWith(normalizedPathname + query + hash); }); + it('should allow configuration to work with hash-based routing', () => { + const url = 'https://google.com'; + const pathname = '/custom/route'; + const normalizedPathname = 'foo'; + const query = '?query=1&query2=3'; + const hash = '#new/hash'; + const combinedUrl = url + '#' + pathname + query + hash; + const $rootScope = jasmine.createSpyObj('$rootScope', ['$on']); + + upgradeModule.$injector.get.and.returnValue($rootScope); + LocationMock.normalize.and.returnValue(normalizedPathname); + + setUpLocationSync(upgradeModule, 'hash'); + + const callback = $rootScope.$on.calls.argsFor(0)[1]; + callback({}, combinedUrl, ''); + + expect(LocationMock.normalize).toHaveBeenCalledTimes(1); + expect(LocationMock.normalize).toHaveBeenCalledWith(pathname); + + expect(RouterMock.navigateByUrl).toHaveBeenCalledTimes(1); + expect(RouterMock.navigateByUrl).toHaveBeenCalledWith(normalizedPathname + query + hash); + }); + it('should work correctly on browsers that do not start pathname with `/`', () => { const anchorProto = HTMLAnchorElement.prototype; const originalDescriptor = Object.getOwnPropertyDescriptor(anchorProto, 'pathname'); @@ -98,4 +122,5 @@ describe('setUpLocationSync', () => { Object.defineProperty(anchorProto, 'pathname', originalDescriptor !); } }); + }); diff --git a/tools/public_api_guard/router/upgrade.d.ts b/tools/public_api_guard/router/upgrade.d.ts index 0ea2ceed35..3245f77cef 100644 --- a/tools/public_api_guard/router/upgrade.d.ts +++ b/tools/public_api_guard/router/upgrade.d.ts @@ -5,4 +5,4 @@ export declare const RouterUpgradeInitializer: { deps: (typeof UpgradeModule)[]; }; -export declare function setUpLocationSync(ngUpgrade: UpgradeModule): void; +export declare function setUpLocationSync(ngUpgrade: UpgradeModule, urlType?: 'path' | 'hash'): void;