diff --git a/aio/src/app/shared/location.service.spec.ts b/aio/src/app/shared/location.service.spec.ts index a42844bb85e..1fff1357b27 100644 --- a/aio/src/app/shared/location.service.spec.ts +++ b/aio/src/app/shared/location.service.spec.ts @@ -436,6 +436,14 @@ describe('LocationService', () => { expect(result).toBe(false); }); + it('local fragment-only URL', () => { + location.internalPath = '/some/path'; + anchor.href = '#some-fragment'; + const result = service.handleAnchorClick(anchor); + expect(service.go).toHaveBeenCalledWith('/some/path#some-fragment'); + expect(result).toBe(false); + }); + it('local url with query params', () => { anchor.href = 'some/local/url?query=xxx&other=yyy'; const result = service.handleAnchorClick(anchor); diff --git a/aio/src/app/shared/location.service.ts b/aio/src/app/shared/location.service.ts index 41d7ff6662c..0d314929362 100644 --- a/aio/src/app/shared/location.service.ts +++ b/aio/src/app/shared/location.service.ts @@ -145,11 +145,16 @@ export class LocationService { } const { pathname, search, hash } = anchor; - const relativeUrl = pathname + search + hash; + // Fix in-page anchors that are supposed to point to fragments inside the page, but are resolved + // relative the the root path (`/`), due to the base URL being set to `/`. + // (See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base#in-page_anchors.) + const isInPageAnchor = anchor.getAttribute('href')?.startsWith('#') ?? false; + const correctPathname = isInPageAnchor ? this.location.path() : pathname; + const relativeUrl = correctPathname + search + hash; this.urlParser.href = relativeUrl; // don't navigate if external link or has extension - if ( anchor.href !== this.urlParser.href || + if ( (!isInPageAnchor && anchor.href !== this.urlParser.href) || !/\/[^/.]*$/.test(pathname) ) { return true; }