Juana Cosgrove
2 min readSep 1, 2021

--

Angular — use APP_BASE_HREF to dynamically calculate case-insenstive baseHref

Use case

Let’s say you are building an app with multiple modules and you want all your app’s baseHref to be case-insensitive, so that when no matter visiting /baseHref/route or /BaseHref/route all are able to be redirect to /route successfully (most of the time you probably would handle this in backend or configuration level, but assume for whatever reason you want to handle it in client side).

What’s the tricky part?
At first glance, you probably would think there might be something you can do to handle it in Router level somewhere, at least that’s where I fell through at the first try. After digging into angular’s routing process, I finally realize that baseHref is a low level thing that should be handled before even passing to do routing calculation.

What’s the default behavior?

Assume baseHref='baseHref' , when visiting a url http://xxxx/BASEHREF/route?param='param' , the routes are calculated in the follow processes:

  1. default PathLocationStrategy calculates path with normalizing query qarameters and with platformLocation.pathname as it is (see How angular location_strategy calculates path)
  2. then Location calcultes path by removing the baseHref (see location.ts). because baseHref='baseHref' , visiting URL’s BASEHREF is not matching the baseHref , Location ‘s Path would be calculated as /BASEHREF/route?param='param' other than expected /route?param='param'
  3. angular’s Router module then would navigate to /BASEHREF/route other than the expected /route

Solution

So if dynamcally calculate baseHref based on the visiting URL(eg: if configured baseHref=’baseHref' , when visiting http://xxxx/BASEHREF/route dynamically set baseHref='BASEHREF'), then in process 2) Location would calculate path correctly.

step1: provide APP_BASE_HREF in the app module with custom factory CaseInsensitiveBaseHref and deps: [PlatformLocation]

providers: [  {    provide: APP_BASE_HREF,    useFactory: CaseInsensitiveBaseHref,    deps: [PlatformLocation],  }],

step2: create a CaseInsensitiveBaseHref function to calculate baseHref based on PlatformLocation.getBaseHrefFromDom() as follows.
Note: below function hanldes couple edge cases based on my project requirements, you can twist it a bit based on your own project needs, you get the idea.

function CaseInsensitiveBaseHrefFactory(platformLocation: PlatformLocation): string {
const path = platformLocation.pathname;
const baseHrefFromDOM = platformLocation.getBaseHrefFromDOM();
// Get baseHref from Dom and remove start and end backslash.
const baseHref = baseHrefFromDOM.replace(/(^\/*|\/*$)/g, '');
// Case-insensitive match baseHref in the path ignoring start backslash.
const caseInSensitiveBaseHrefRegexp = new RegExp(`^\/*${baseHref}`, 'i');
const matchedBaseHref = path.match(caseInSensitiveBaseHrefRegexp);

if (matchedBaseHref) {
const remainingPath = path.slice(matchedBaseHref[0].length);
// Deal with case which contains basePath but should not use matchedBaseHref. Eg: base = 'base', path='BaseBall'.
// matchedBaseHref is the end of the path or follows with white space or a new segment which starts with backslash.
const isValidMatch = !remainingPath || !!remainingPath.match(/^[\/\s]/);
return isValidMatch ? matchedBaseHref[0] : baseHrefFromDOM;
}
return baseHrefFromDOM;
}

The end!

--

--