89

How would I remove a query parameter from the URL? For example from www.expample.com/home?id=123&pos=sd&sd=iii to www.expample.com/home?id=123&sd=iii

EDIT: This is my version:

this.activatedRoute.queryParams.subscribe(c => {
  const params = Object.assign({}, c);
  delete params.dapp;
  this.router.navigate([], { relativeTo: this.activatedRoute, queryParams: params });
}).unsubscribe();
Jabster28
  • 177
  • 11
Nazar Kalytiuk
  • 1,499
  • 1
  • 11
  • 21

9 Answers9

251

You can remove a query parameter by using the merge option of queryParamsHandling and passing in null for any params you wish to remove.

// Remove query params
this.router.navigate([], {
  queryParams: {
    'yourParamName': null,
    'youCanRemoveMultiple': null,
  },
  queryParamsHandling: 'merge'
})

This option is simpler and requires less work to ensure you are not removing other params. You also do not need to worry about cleaning up an observable subscription when your component is destroyed.

Dzinx
  • 55,586
  • 10
  • 60
  • 78
epelc
  • 5,300
  • 5
  • 22
  • 27
  • 1
    Any ideas how to remove a single item from a query parameter that is an array (e.g. given `/path?p=a&p=b&p=c`, how to remove `p=c` only)? – Trevor Aug 19 '20 at 08:55
  • 1
    This way of doing it works especially well when you have dynamic query params that come from other parts of the app and you only want to remove very specific params without interfering with what else might have been added somewhere else. – Geo242 Sep 04 '20 at 15:11
  • 3
    It is worth noting that this will trigger navigation event. I had an issue when clearing the params within angular guard - navigation was cancelled – Marek Dec 22 '20 at 12:03
  • 1
    You can use the option `skipLocationChange` to prevent it from triggering a navigation event. – Jorik Mar 30 '21 at 08:10
  • Be aware that `router.navigate()` is asynchronous. So if you try to remove two query params by calling `router.navigate()` twice within the same task (event loop frame) - only the second param will actually be deleted from the url. – amakhrov Apr 23 '21 at 02:09
31

UPDATE: @epelc's answer below is the up-to-date and correct way to do this: https://stackoverflow.com/a/52193044/5932590.


Unfortunately, there is no clear-cut way to do this currently: https://github.com/angular/angular/issues/18011. However, as jasonaden commented on the linked thread,

This could be done manually by merging the old and new query params, removing the key you don't want.

Here is one way to do that:

Let's say you have your queryParams stored in some properties.

class MyComponent() {
  id: string;
  pos: string;
  sd: string;

  constructor(private route: ActivatedRoute, private router: Router) {}

  ngOnInit() {
    this.route.url.subscribe(next => {
      const paramMap = next.queryParamMap;
      this.id = paramMap.get('id');
      this.pos = paramMap.get('pos');
      this.sd = paramMap.get('sd');
    });
  }
}

A method to clear the pos parameter would look like this:

clearPosParam() {
  this.router.navigate(
    ['.'], 
    { relativeTo: this.route, queryParams: { id: this.id, sd: this.sd } }
  );
}

This will effectively navigate to the current route and clear your pos query parameter, keeping your other query parameters the same.

vince
  • 7,808
  • 3
  • 34
  • 41
  • 1
    Glad to help, consider "accepting" the answer by clicking the checkmark so other people know your question has been answered. And welcome to SO! – vince Feb 01 '18 at 00:51
  • 4
    This leaks an observable subscription. `Router` does not automatically cleanup the subscription to `route.url.subscribe` and must be manually tracked and disposed when the component is destroyed. Please consider my answer below which doesn't require any subscriptions and is simpler. – epelc Sep 05 '18 at 20:36
  • I prefer this to @epelc's answer because I don't have to specify what properties of the query params object I want to clear. I'm working on a generic faceted search component, I don't know the properties in the component that's implementing this, I just need that component to manage adding and removing values and I prefer to only specify properties that actually have a value to keep the url short. – J Scott Sep 09 '22 at 17:57
3

This is the best sulotion that i found, you can change url parameters

in constructor use

    private _ActivatedRoute: ActivatedRoute

then use this in init or in constructor body

    var snapshot = this._ActivatedRoute.snapshot;
    const params = { ...snapshot.queryParams };
    delete params.pos
    this.router.navigate([], { queryParams: params });
Mohammad Hassani
  • 511
  • 6
  • 14
3

I was looking to do exactly this, but without using the router. Here is what I came up with:

import { Location } from '@angular/common';
import { HttpParams } from '@angular/common/http';

declare location: Location; // get this from dependency injection

const [path, query] = location.path().split('?');
const params = new HttpParams({ fromString: query });
const theValueIWant = params.get('theParamIWant');
location.replaceState(path, params.delete('theParamIWant').toString());
Eric Simonton
  • 5,702
  • 2
  • 37
  • 54
2

Removing Query Params:

import { Router, ActivatedRoute, Params } from '@angular/router';

constructor(private router: Router, private activatedRoute: ActivatedRoute){
}

setQueryParams(){
    const qParams: Params = {};
    this.router.navigate([], {
        relativeTo: this.activatedRoute,
        queryParams: qParams,
        queryParamsHandling: ''
    });
}
NullDev
  • 6,739
  • 4
  • 30
  • 54
s srinivas
  • 39
  • 1
1

You can use native javascript operation to remove queryParams from url and navigate to View using navigateByUrl method

https://angular.io/api/router/Router#navigateByUrl

this.route.queryParams
      .subscribe((params: Params) => {
        if (params && Object.keys(params).length > 0) {
          const urlWithoutQueryParams = this.router.url.substring(0, this.router.url.indexOf('?'));
          this.router.navigateByUrl(urlWithoutQueryParams)
            .then(() => {
            // any other functionality when navigation succeeds
              params = null;
            });
        }
      });
   
khizer
  • 1,242
  • 15
  • 13
1

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&param2=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&param2=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&param2=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&param2=test2&param3=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&param3=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))
        );
    });
};

Johan Aspeling
  • 765
  • 1
  • 13
  • 38
0

This worked for me:

Step 1: Declare a global url search param.

  incomingUrlParams: URLSearchParams;

Step 2: Save the query in the urlsearchparam global variable

this.incomingUrlParams = new URLSearchParams(window.location.search);

Step 3: Call this anywhere when the params has been saved:

clearQueryParamenters() {
      let queryParamsJsonString: string = "";      
      this.incomingUrlParams.forEach(function(value, key) {
        queryParamsJsonString += '"' + key + '":' + null + ',';
      });
      queryParamsJsonString = "{" + queryParamsJsonString.trim().replace(/(^,)|(,$)/g, "") + "}";
      this.router.navigate([], {
        queryParams: JSON.parse(queryParamsJsonString),
        queryParamsHandling: 'merge'
      })
  }
Gama Sharma
  • 51
  • 1
  • 7
-1

None of the above solution was fine for me. Until i tried this approach.

import { Component } from '@angular/core';
import { Location } from '@angular/common';

@Component({
  selector: 'app-my-component',
  templateUrl: './my-component.component.html',
  styleUrls: ['./my-component.component.css']
})
export class MyComponentComponent {
  constructor(private location: Location) { }

  changeUrl() {
    const newUrl = '/prepare/this/url/yourself/and/exclude/parameter';
    this.location.replaceState(newUrl);
  }
}

This replaces the parameter's version of URL with newUrl and good thing is that the components don't get re-rendered.
For more info about replaceState here it is.