I've written a few Router Prototype overrides that makes things easier to handle query params:
The idea is to call a method on the router to easily manage routing via parameters, instead of having to export functions/redeclare the functionality every time.
Create an index.d.ts
file that contains the prototype override definitions:
// Ensure this is treated as a module.
export { };
declare module '@angular/router' {
interface Router {
updateQueryParams(activatedRoute: ActivatedRoute, params: Params): Promise<boolean>;
setQueryParams(activatedRoute: ActivatedRoute, params: Params): Promise<boolean>;
removeQueryParams(activatedRoute: ActivatedRoute, ...keys: string[]): Promise<boolean>;
}
}
Important:
Make sure you import this file before using this prototype override, I just added my prototype import(s) to the app.module.ts
:
import './shared/prototype-overrides/router.prototypes';
Setting Query Parameters
This will only set the query parameters specified, and not merge the parameters.
Scenario
You are on the following route:
http://localhost:4200/#/some-route?param1=Test¶m2=test2
and you want to SET the query parameters to param3=HelloWorld
, removing the others.
Usage
this.router.setQueryParams(this.activatedRoute, { param3: 'HelloWorld' });
// Will route to http://localhost:4200/#/some-route?param3=HelloWorld
Prototype function implementation
Router.prototype.setQueryParams = function (activatedRoute: ActivatedRoute, params: Params): Promise<boolean> {
const context: Router = this;
if (isNullOrUndefined(activatedRoute)) {
throw new Error('Cannot update the query parameters - Activated Route not provided to use relative route');
}
return new Promise<boolean>((resolve) => {
setTimeout(() => {
resolve(context.navigate([], {
relativeTo: activatedRoute,
queryParams: params
}));
});
});
};
Updating Query Parameters
This is used to just easily update the queryParams, which will merge the query parameters in the route, so you don't have duplicate query parameters.
Scenario
You are on the following route:
http://localhost:4200/#/some-route?param1=Test¶m2=test2
and you want to UPDATE only the one query parameter, param1
to param1=HelloWorld
, and leave the others as they are.
Usage
this.router.updateQueryParams(this.activatedRoute, { param1: 'HelloWorld' });
// Will route to http://localhost:4200/#/some-route?param1=HelloWorld¶m2=test2
Prototype function implementation
Router.prototype.updateQueryParams = function (activatedRoute: ActivatedRoute, params: Params): Promise<boolean> {
const context: Router = this;
if (isNullOrUndefined(activatedRoute)) {
throw new Error('Cannot update the query parameters - Activated Route not provided to use relative route');
}
// setTimeout required because there is an unintended behaviour when rapidly firing router updates in the same repaint cycle:
//
// NavigationCancel - Navigation ID 2 is not equal to the current navigation id 3
// https://stackoverflow.com/a/42802182/1335789
return new Promise<boolean>((resolve) => {
setTimeout(() => {
resolve(context.navigate([], {
relativeTo: activatedRoute,
queryParams: params,
queryParamsHandling: 'merge'
}));
});
});
};
Removing Query Parameters
Scenario
You are on the following route:
http://localhost:4200/#/some-route?param1=Test¶m2=test2¶m3=test3
and you want to REMOVE only the one (or more, separated keys by string) query parameter, param1
, and leave the others as they are.
Usage
this.router.removeQueryParams(this.activatedRoute, 'param1');
// Will route to http://localhost:4200/#/some-route?param2=test2¶m3=test3
//Removing multiple parameters:
this.router.removeQueryParams(this.activatedRoute, 'param1', 'param3');
// Will route to http://localhost:4200/#/some-route?param2=test2
Prototype function implementation
Router.prototype.removeQueryParams = function (activatedRoute: ActivatedRoute, ...keys: string[]): Promise<boolean> {
const context: Router = this;
const currentParams: any = {};
Object.keys(activatedRoute.snapshot.queryParams).forEach(key => {
currentParams[key] = activatedRoute.snapshot.queryParams[key];
});
keys?.forEach(key => {
delete currentParams[key];
});
return new Promise<boolean>((resolve) => {
setTimeout(() =>
resolve(context.setQueryParams(activatedRoute, currentParams))
);
});
};