Skip to content

Commit

Permalink
feat(router): add hash-based navigation option to setUpLocationSync
Browse files Browse the repository at this point in the history
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 angular#24429 angular#21995
  • Loading branch information
jasonaden committed Feb 8, 2019
1 parent f2a734b commit 7176dc3
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 3 deletions.
12 changes: 10 additions & 2 deletions packages/router/upgrade/src/upgrade.ts
Expand Up @@ -58,7 +58,7 @@ export function locationSyncBootstrapListener(ngUpgrade: UpgradeModule) {
* *
* @publicApi * @publicApi
*/ */
export function setUpLocationSync(ngUpgrade: UpgradeModule) { export function setUpLocationSync(ngUpgrade: UpgradeModule, urlType: 'path' | 'hash' = 'path') {
if (!ngUpgrade.$injector) { if (!ngUpgrade.$injector) {
throw new Error(` throw new Error(`
RouterUpgradeInitializer can be used only after UpgradeModule.bootstrap has been called. RouterUpgradeInitializer can be used only after UpgradeModule.bootstrap has been called.
Expand All @@ -71,7 +71,15 @@ export function setUpLocationSync(ngUpgrade: UpgradeModule) {


ngUpgrade.$injector.get('$rootScope') ngUpgrade.$injector.get('$rootScope')
.$on('$locationChangeStart', (_: any, next: string, __: string) => { .$on('$locationChangeStart', (_: any, next: string, __: string) => {
const url = resolveUrl(next); let url;
if (urlType === 'path') {
url = resolveUrl(next);
} else if (urlType === 'hash') {
// Remove the leading hash from the URL
url = resolveUrl(next.substring(1));
} else {
throw 'Invalid URLType passed to setUpLocationSync: ' + urlType;
}
const path = location.normalize(url.pathname); const path = location.normalize(url.pathname);
router.navigateByUrl(path + url.search + url.hash); router.navigateByUrl(path + url.search + url.hash);
}); });
Expand Down
25 changes: 25 additions & 0 deletions packages/router/upgrade/test/upgrade.spec.ts
Expand Up @@ -79,6 +79,30 @@ describe('setUpLocationSync', () => {
expect(RouterMock.navigateByUrl).toHaveBeenCalledWith(normalizedPathname + query + hash); 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 + query + hash);

expect(RouterMock.navigateByUrl).toHaveBeenCalledTimes(1);
expect(RouterMock.navigateByUrl).toHaveBeenCalledWith(normalizedPathname + query + hash);
});

it('should work correctly on browsers that do not start pathname with `/`', () => { it('should work correctly on browsers that do not start pathname with `/`', () => {
const anchorProto = HTMLAnchorElement.prototype; const anchorProto = HTMLAnchorElement.prototype;
const originalDescriptor = Object.getOwnPropertyDescriptor(anchorProto, 'pathname'); const originalDescriptor = Object.getOwnPropertyDescriptor(anchorProto, 'pathname');
Expand All @@ -98,4 +122,5 @@ describe('setUpLocationSync', () => {
Object.defineProperty(anchorProto, 'pathname', originalDescriptor !); Object.defineProperty(anchorProto, 'pathname', originalDescriptor !);
} }
}); });

}); });
2 changes: 1 addition & 1 deletion tools/public_api_guard/router/upgrade.d.ts
Expand Up @@ -5,4 +5,4 @@ export declare const RouterUpgradeInitializer: {
deps: (typeof UpgradeModule)[]; deps: (typeof UpgradeModule)[];
}; };


export declare function setUpLocationSync(ngUpgrade: UpgradeModule): void; export declare function setUpLocationSync(ngUpgrade: UpgradeModule, urlType?: 'path' | 'hash'): void;

0 comments on commit 7176dc3

Please sign in to comment.