Skip to content

Commit 71d0eeb

Browse files
jasonadenIgorMinar
authored andcommitted
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
1 parent 295a143 commit 71d0eeb

File tree

3 files changed

+37
-3
lines changed

3 files changed

+37
-3
lines changed

packages/router/upgrade/src/upgrade.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export function locationSyncBootstrapListener(ngUpgrade: UpgradeModule) {
5858
*
5959
* @publicApi
6060
*/
61-
export function setUpLocationSync(ngUpgrade: UpgradeModule) {
61+
export function setUpLocationSync(ngUpgrade: UpgradeModule, urlType: 'path' | 'hash' = 'path') {
6262
if (!ngUpgrade.$injector) {
6363
throw new Error(`
6464
RouterUpgradeInitializer can be used only after UpgradeModule.bootstrap has been called.
@@ -71,7 +71,16 @@ export function setUpLocationSync(ngUpgrade: UpgradeModule) {
7171

7272
ngUpgrade.$injector.get('$rootScope')
7373
.$on('$locationChangeStart', (_: any, next: string, __: string) => {
74-
const url = resolveUrl(next);
74+
let url;
75+
if (urlType === 'path') {
76+
url = resolveUrl(next);
77+
} else if (urlType === 'hash') {
78+
// Remove the first hash from the URL
79+
const hashIdx = next.indexOf('#');
80+
url = resolveUrl(next.substring(0, hashIdx) + next.substring(hashIdx + 1));
81+
} else {
82+
throw 'Invalid URLType passed to setUpLocationSync: ' + urlType;
83+
}
7584
const path = location.normalize(url.pathname);
7685
router.navigateByUrl(path + url.search + url.hash);
7786
});

packages/router/upgrade/test/upgrade.spec.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,30 @@ describe('setUpLocationSync', () => {
7979
expect(RouterMock.navigateByUrl).toHaveBeenCalledWith(normalizedPathname + query + hash);
8080
});
8181

82+
it('should allow configuration to work with hash-based routing', () => {
83+
const url = 'https://google.com';
84+
const pathname = '/custom/route';
85+
const normalizedPathname = 'foo';
86+
const query = '?query=1&query2=3';
87+
const hash = '#new/hash';
88+
const combinedUrl = url + '#' + pathname + query + hash;
89+
const $rootScope = jasmine.createSpyObj('$rootScope', ['$on']);
90+
91+
upgradeModule.$injector.get.and.returnValue($rootScope);
92+
LocationMock.normalize.and.returnValue(normalizedPathname);
93+
94+
setUpLocationSync(upgradeModule, 'hash');
95+
96+
const callback = $rootScope.$on.calls.argsFor(0)[1];
97+
callback({}, combinedUrl, '');
98+
99+
expect(LocationMock.normalize).toHaveBeenCalledTimes(1);
100+
expect(LocationMock.normalize).toHaveBeenCalledWith(pathname);
101+
102+
expect(RouterMock.navigateByUrl).toHaveBeenCalledTimes(1);
103+
expect(RouterMock.navigateByUrl).toHaveBeenCalledWith(normalizedPathname + query + hash);
104+
});
105+
82106
it('should work correctly on browsers that do not start pathname with `/`', () => {
83107
const anchorProto = HTMLAnchorElement.prototype;
84108
const originalDescriptor = Object.getOwnPropertyDescriptor(anchorProto, 'pathname');
@@ -98,4 +122,5 @@ describe('setUpLocationSync', () => {
98122
Object.defineProperty(anchorProto, 'pathname', originalDescriptor !);
99123
}
100124
});
125+
101126
});

tools/public_api_guard/router/upgrade.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ export declare const RouterUpgradeInitializer: {
55
deps: (typeof UpgradeModule)[];
66
};
77

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

0 commit comments

Comments
 (0)