Parse URL in Angular
Recently, I had a requirement to parse the browser URL into URL parts and extract the query string part in Angular application. With Angular 1.x, it was simple to just inject $location
and read $location.search().querystringName
.
But, with Angular 2+, these kind of URL parse functions were moved into @angular.router
. If your application already requires Routing Module, then go-ahead and simply import & parse url as given below
import { DefaultUrlSerializer } from '@angular/router';?
import { Location, LocationStrategy, PathLocationStrategy } from '@angular/common';
@Component({
selector: 'my-component',
providers: [Location, { provide: LocationStrategy, useClass: PathLocationStrategy }],
})
export class MyComponent{
constructor(
private config: ConfigService,
private location: Location,
private urlUtility: UrlUtility) {
var urlObj : UrlTree = new DefaultUrlSerializer(this.location.path());
}
}
Further, if your requirement is to just read URL route parameters then go through post on "reading URL parameters in Angular".
Or else, if you just need a URL parse method features, then Performing above import, will result in entire router library being loaded/included in bundle (unnecessary bloat).
Because Angular Routing lib is actually an ES5 - single UMD(Universal Module Definition) but sugar coated using TypeScript definition files, that gives an illusion like ES6 import & exports.
Alternate Solution
So in-order to optimize my application bundle size., I decided to pick up an alternate URL Parsing library from NPM, that should work fine for both in client/browser and NodeJs environments. After a long search, I've settled with url-parse which has a small footprint and performs all required operations on URL string ( It looks to be recent project and still active in development).
// UrlObject.ts
interface IHashTable<T> {
[key: string]: T;
}
export declare class UrlObject {
public protocol: string;
public slashes: boolean;
public auth: string;
public username: string;
public password: string;
public host: string;
public hostname: string;
public port: number;
public pathname: string;
public query: IHashTable<string>;
public hash: string;
public href: string;
public origin: string;
public set(key: string, value: string): void;
public toString(): string;
}
//url-utility.ts
import { UrlObject } from '../dto';
import { Injectable } from '@angular/core';
import * as urlParse from 'url-parse';
@Injectable()
export class UrlUtility {
public parse(url: string, parseQuery= true): UrlObject {
return urlParse(url, parseQuery);
}
}
Then in your Angular component, you can import above service and use it as shown below
//my-component.ts
import { Location, LocationStrategy, PathLocationStrategy } from '@angular/common';
import { UrlObject } from './dto';
@Component({
selector: 'my-component',
styleUrls: [],
providers: [Location, { provide: LocationStrategy, useClass: PathLocationStrategy }],
})
export class MyComponent{
constructor(
private config: ConfigService,
private location: Location,
private urlUtility: UrlUtility) {
let url: UrlObject = this.urlUtility.parse(this.location.path());
}
}
When importing or requiring a module, care should be taken to verify if an import is indeed picking up the required piece of code OR does it bring lot of junk & un-used code into bundle. An extra review of generated bundle using Webpack-bundle-Analyzer
will tell you a lot on the bloat a require statement would do.
Follow the mantra: IMPORT WITH CARE