340

In a web application that makes use of AJAX calls, I need to submit a request but add a parameter to the end of the URL, for example:

Original URL:

http://server/myapp.php?id=10

Resulting URL:

http://server/myapp.php?id=10&enabled=true

Looking for a JavaScript function which parses the URL looking at each parameter, then adds the new parameter or updates the value if one already exists.

Lessan Vaezi
  • 5,257
  • 3
  • 23
  • 15
  • 1
    I had a similar scenario once and I found [this article](http://www.eggheadcafe.com/articles/20020107.asp) by Peter Bromberg very helpful : – Cerebrus Jan 28 '09 at 09:01
  • Have you searched for [javascript url parsers](http://www.google.com/search?hl=en&rlz=1C1GGLS_nbNO293NO303&q=javascript+url+parser&btnG=Search) ? You could make your own, splitting on every &-character, but it's probably easier just to use existing code. – csl Jan 28 '09 at 08:38
  • 2
    window.history.pushState('page2', 'Title', document.location+'/page2.php'); will do your work without loading page – Rutunj sheladiya Nov 04 '15 at 06:33
  • 1
    This question have better answers here http://stackoverflow.com/questions/6953944/how-to-add-parameters-to-a-url-that-already-contains-other-parameters-and-maybe/6954277 – rkb Jan 12 '17 at 12:53
  • unbelievable this isnt native in this poor language that JS is.... – bohr Jun 08 '18 at 10:33
  • This is very nice and lightweight library: https://medialize.github.io/URI.js/ – Piotr Kowalski Oct 28 '19 at 12:08

33 Answers33

407

You can use one of these:

Example:

var url = new URL("http://foo.bar/?x=1&y=2");

// If your expected result is "http://foo.bar/?x=1&y=2&x=42"
url.searchParams.append('x', 42);

// If your expected result is "http://foo.bar/?x=42&y=2"
url.searchParams.set('x', 42);
PaK-Zer0
  • 55
  • 12
Vianney Bajart
  • 4,615
  • 1
  • 10
  • 10
  • 3
    I'd like to add a query parameter without a value, e.g. adding `XML` to `http://foo.bar/?x=1&y=2` so that the end result is `http://foo.bar/?x=1&y=2&XML`. Is this possible? I tried `url.searchParams.set('XML');`, `url.searchParams.set('XML', null);`, and `url.searchParams.set('XML', undefined);` - but none worked in *Chrome 63*. – Abdull Dec 29 '17 at 15:04
  • 2
    Thanks! Too bad it is not supported by iOS, yet. https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams – kanji Mar 18 '18 at 03:35
  • 35
    Too bad IE doesn't support it. – spedy Mar 20 '18 at 08:34
  • 4
    iOS does now support URLSearchParams (since 9 days after @kanji's comment) – MJeffryes Mar 27 '18 at 16:29
  • 11
    Good news @MJeffryes! Still not supported by IE and Netscape. – Vianney Bajart Mar 28 '18 at 19:48
  • 2
    Yes it's bad supported by IE, but there is a polyfill that can handle that: https://github.com/lifaon74/url-polyfill – Az.Youness Mar 26 '19 at 00:29
  • Are you sure you can modify the URLs searchParams like that? The doc says the property is readonly allowing get access. – Mike Lippert Dec 12 '19 at 16:48
  • 2
    `url.searchParams` is a read-only reference to a `URLSearchParams` object. It means than you cannot do: `url.searchParam = new URLSearchParam();` But you can modify in-place the content of the object using `.set()`. It's like: `const a = {b: 0}` You cannot modify the reference: `a = {b: 1}` but you can modify the content of the object in-place: `a.b = 1` Try it in your JS console ;-) – Vianney Bajart Dec 12 '19 at 21:48
  • 1
    This is definitely the best answer in 2020 (2021) - if your target browser(s) don't support it, I suggest using a polyfill (e.g. from polyfill.io) – Emzaw Jan 18 '21 at 15:42
  • @Abdull, have you tried `url.searchParams.set('XML', '')`? – Andrey Mikhaylov - lolmaus Mar 24 '21 at 07:07
  • @AndreyMikhaylov-lolmaus, certainly, you haven't tried `url.searchParams.set('XML', '')` either, because it doesn't work. – Abdull Mar 25 '21 at 08:01
  • @Abdull You're right, I hadn't tried it. But I've tried it just now and it does work. Why wouldn't it? `const foo = new URLSearchParams(); foo.set('XML', ''); foo.toString() // => "XML="` – Andrey Mikhaylov - lolmaus Mar 25 '21 at 11:05
  • @AndreyMikhaylov-lolmaus, read my initial question again. `XML` vs `XML=`. – Abdull Mar 25 '21 at 23:17
  • By my upvote it became `404` – AmerllicA May 23 '21 at 21:23
215

A basic implementation which you'll need to adapt would look something like this:

function insertParam(key, value) {
    key = encodeURIComponent(key);
    value = encodeURIComponent(value);

    // kvp looks like ['key1=value1', 'key2=value2', ...]
    var kvp = document.location.search.substr(1).split('&');
    let i=0;

    for(; i<kvp.length; i++){
        if (kvp[i].startsWith(key + '=')) {
            let pair = kvp[i].split('=');
            pair[1] = value;
            kvp[i] = pair.join('=');
            break;
        }
    }

    if(i >= kvp.length){
        kvp[kvp.length] = [key,value].join('=');
    }

    // can return this or...
    let params = kvp.join('&');

    // reload page with new params
    document.location.search = params;
}

This is approximately twice as fast as a regex or search based solution, but that depends completely on the length of the querystring and the index of any match


the slow regex method I benchmarked against for completions sake (approx +150% slower)

function insertParam2(key,value)
{
    key = encodeURIComponent(key); value = encodeURIComponent(value);

    var s = document.location.search;
    var kvp = key+"="+value;

    var r = new RegExp("(&|\\?)"+key+"=[^\&]*");

    s = s.replace(r,"$1"+kvp);

    if(!RegExp.$1) {s += (s.length>0 ? '&' : '?') + kvp;};

    //again, do what you will here
    document.location.search = s;
}
annakata
  • 70,224
  • 16
  • 111
  • 179
  • 2
    thanks again. see http://www.lessanvaezi.com/wp-content/uploads/2009/01/test.html for a basic comparison of the methods – Lessan Vaezi Jan 28 '09 at 20:13
  • Nice function, annakata :) but in many cases, url parameters are case insensitive. Wouldn't it be wise to make the function case insensitive as well? – Jens Roland Nov 19 '10 at 09:50
  • 16
    Using escape() to escape URL parameters is wrong. It breaks for values with "+" in them. You should be using encodeURIComponent instead. Full discussion: http://xkr.us/articles/javascript/encode-compare – Antonin Hildebrand Jun 09 '11 at 17:52
  • 5
    I am calling this function and the page is reloading in infinite loop. Please help! – sumit Jul 24 '11 at 16:34
  • @iSumitG instead of location.search you can use location.hash so it won't reload ... just replace all the instances of location.search with location.hash – ip. Sep 12 '11 at 16:40
  • @Darwin I wouldn't say it is wrong, just different from what you might expect. One could just as easily say it is wrong to use values with `+` in them. – Muhd Dec 01 '11 at 02:51
  • Top implementation doesn't handle empty location.search properly. See Mehdi's answer for updated solution. – Muhd Dec 01 '11 at 22:38
  • 6
    when no parameters are already in the url you get a ?&param=value – Roy Toledo Aug 23 '12 at 12:44
  • and this function doesn't support multiple addition of querystring. – Murtaza Khursheed Hussain Mar 18 '13 at 10:00
  • 9
    Shouldn't you be using `encodeURIComponent` rather than `encodeURI`? Otherwise any characters like `=`, `&` in your name or value will corrupt the URI. – Adrian Pronk May 12 '14 at 21:38
  • 2
    I was inspired by the first solution - good idea, but not-readable code and it does not support more params at once, so I've made a **new one that does accept an object with `key: value,` pairs and it is easily understand-able https://jsfiddle.net/1u9fqad3/1/** *UPDATE: fixed case when document.location.search is empty or 1 char* – jave.web Jul 08 '16 at 19:33
  • 2
    downvoted because it has bugs that were never fixed :) – Daij-Djan Dec 07 '16 at 14:20
105
const urlParams = new URLSearchParams(window.location.search);

urlParams.set('order', 'date');

window.location.search = urlParams;

.set first agrument is the key, the second one is the value.

Zoidbergseasharp
  • 1,544
  • 1
  • 6
  • 11
66

Thank you all for your contribution. I used annakata code and modified to also include the case where there is no query string in the url at all. Hope this would help.

function insertParam(key, value) {
        key = escape(key); value = escape(value);

        var kvp = document.location.search.substr(1).split('&');
        if (kvp == '') {
            document.location.search = '?' + key + '=' + value;
        }
        else {

            var i = kvp.length; var x; while (i--) {
                x = kvp[i].split('=');

                if (x[0] == key) {
                    x[1] = value;
                    kvp[i] = x.join('=');
                    break;
                }
            }

            if (i < 0) { kvp[kvp.length] = [key, value].join('='); }

            //this will reload the page, it's likely better to store this until finished
            document.location.search = kvp.join('&');
        }
    }
Muhd
  • 20,699
  • 20
  • 59
  • 72
Mehdi
  • 677
  • 5
  • 2
62

This is very simple solution. Its doesn't control parameter existence, and it doesn't change existing value. It adds your parameter to end, so you can get latest value in your back-end code.

function addParameterToURL(param){
    _url = location.href;
    _url += (_url.split('?')[1] ? '&':'?') + param;
    return _url;
}
Mehmet Fatih Yıldız
  • 1,526
  • 14
  • 23
  • 7
    you should also account for "#" in the url.. here's some code slop: `url = (url.indexOf("?") != -1 ? url.split("?")[0]+"?"+part+"&"+url.split("?")[1] : (url.indexOf("#") != -1 ? url.split("#")[0]+"?"+part+"#"+ url.split("#")[1] : url+'?'+part));` – kanzure Feb 27 '12 at 22:51
  • 3
    @kanzure this thing looks evil as hell, but it's exactly what I wanted. Thanks. – Chad von Nau Sep 02 '12 at 02:44
  • why split the url to check for the existence of a single character? also don't forget to encode...something more like `function appendQs(url, key, value) { return url + (url.indexOf('?') >= 0 ? "&" : '?') + encodeURIComponent(key) + "=" + encodeURIComponent(value); };` – drzaus May 30 '14 at 18:39
  • 1
    Fix it. This function does not check whether the parameter is already supplied. I tested this and got `https://localhost/preview/inventory.html?sortci=priceASC&sortci=priceASC&sortci=stitle`. – Jay Aug 31 '16 at 19:09
  • @Jay, why does it need fixing? Check your assumptions. Duplicate query string parameters are legal, the same as duplicate form fields. This is how checkbox lists are implemented.in HTML and these will get passed via query string if the form method=get. – stephen May 08 '20 at 03:00
  • 3
    @stephen got it :) Turns out I was a dumb kid in '16 :) – Jay May 08 '20 at 09:48
34

Here's a vastly simplified version, making tradeoffs for legibility and fewer lines of code instead of micro-optimized performance (and we're talking about a few miliseconds difference, realistically... due to the nature of this (operating on the current document's location), this will most likely be ran once on a page).

/**
* Add a URL parameter (or changing it if it already exists)
* @param {search} string  this is typically document.location.search
* @param {key}    string  the key to set
* @param {val}    string  value 
*/
var addUrlParam = function(search, key, val){
  var newParam = key + '=' + val,
      params = '?' + newParam;

  // If the "search" string exists, then build params from it
  if (search) {
    // Try to replace an existance instance
    params = search.replace(new RegExp('([?&])' + key + '[^&]*'), '$1' + newParam);

    // If nothing was replaced, then add the new param to the end
    if (params === search) {
      params += '&' + newParam;
    }
  }

  return params;
};

You would then use this like so:

document.location.pathname + addUrlParam(document.location.search, 'foo', 'bar');
dan-lee
  • 13,814
  • 5
  • 48
  • 72
Garrett
  • 465
  • 4
  • 3
  • 2
    +1 I like how you can specify something other than document.location.search – Muhd Nov 29 '11 at 01:06
  • 1
    +1 Awesome, I agree that legibility is more important than micro-optimization in this case and I'm glad to see someone took that approach. @Muhd Maybe that was a bug in the JS engine when you wrote that comment, but I just tested '$1' in this context and it works fine. – JMTyler Feb 02 '14 at 06:36
  • Thanks a lot for the solution, though I also get stuck if I want to replace a value and there is already a parameter there. Instead a & it writes $1 – Codebryo Jan 14 '15 at 10:32
  • 2
    Garrett: Could you fix your answer so it replaces existing parameters correctly? It's just a matter of replacing `[\?&]` with `([\?&])` in the RegExp (I'd just edit it myself but I'm not sure if the community policy allows fixing bugs in answers). – opyh Feb 25 '15 at 20:28
  • This is not working with url like "http://www.domain.tld" its add "&" instead of "?" – user706420 Mar 03 '16 at 11:07
  • This is not working with url like "domain.tld#anchor"; its add "&" after the anchor – user706420 Mar 03 '16 at 13:03
22

/**
* Add a URL parameter 
* @param {string} url 
* @param {string} param the key to set
* @param {string} value 
*/
var addParam = function(url, param, value) {
   param = encodeURIComponent(param);
   var a = document.createElement('a');
   param += (value ? "=" + encodeURIComponent(value) : ""); 
   a.href = url;
   a.search += (a.search ? "&" : "") + param;
   return a.href;
}

/**
* Add a URL parameter (or modify if already exists)
* @param {string} url 
* @param {string} param the key to set
* @param {string} value 
*/
var addOrReplaceParam = function(url, param, value) {
   param = encodeURIComponent(param);
   var r = "([&?]|&amp;)" + param + "\\b(?:=(?:[^&#]*))*";
   var a = document.createElement('a');
   var regex = new RegExp(r);
   var str = param + (value ? "=" + encodeURIComponent(value) : ""); 
   a.href = url;
   var q = a.search.replace(regex, "$1"+str);
   if (q === a.search) {
      a.search += (a.search ? "&" : "") + str;
   } else {
      a.search = q;
   }
   return a.href;
}

url = "http://www.example.com#hashme";
newurl = addParam(url, "ciao", "1");
alert(newurl);

And please note that parameters should be encoded before being appended in query string.

http://jsfiddle.net/48z7z4kx/

freedev
  • 17,230
  • 4
  • 83
  • 98
  • Small memory leak - you'll want to remove the anchor element that was added to the document before returning. – hemp Oct 23 '13 at 22:21
  • @freedev, Nope, I'm not sure. ;) I'm having a hard time finding an authoritative source but the evidence suggests that you are correct. Since the created element is never attached to the DOM, it *should* be cleaned up once the variable goes out of scope. The DOM API isn't particularly well designed when it comes to side effects, so I'm overly cautious. – hemp Oct 24 '13 at 03:52
  • This solution adds a trailing slash to URLs that have no path and reorders parameters, which are unnecessary and possibly undesirable changes. It also appends rather than replacing existing parameters that have no value (e.g. `http://abc.def/?a&b&b`). – Adam Leggett Aug 05 '16 at 20:38
  • @AdamLeggett Thanks for pointing the bug that happens when a request parameter have no value, I have just fixed my answer. The remaining strange behaviors you're talking about, if you're right, are generated by HTML anchor object which usually is a standard browser component. I suggest to double check because very unlikely a browser adds unnecessary or undesirable behaviors. – freedev Aug 07 '16 at 16:19
  • The browser is appending the trailing slash. You are reordering parameters yourself by appending the desired value at the end every time. This isn't wrong per se, but I'd prefer a solution that doesn't do it. You should also not be matching against `&`, as this is not a separator; it is part of the value. Beyond that, this solution just does more work and has more code than necessary. – Adam Leggett Aug 08 '16 at 14:47
  • Excuse me, `&` is not part of the value either. It is just an incorrectly encoded query string. – Adam Leggett Aug 08 '16 at 15:01
  • @AdamLeggett regarding the & I had few problems with w3c HTML validators and had to use & in place of & when writing URLs in HTML. http://htmlhelp.com/tools/validator/problems.html#amp http://stackoverflow.com/questions/4441594/w3c-markup-validator-ampersand-error these problems affected this routine too. – freedev Aug 08 '16 at 21:34
  • @AdamLeggett A properly written application will find a given query parameter in any order and it shouldn't be order sensitive. Anyway, I have to admit that this solution waste a little of resources manipulating the parameters, so I have just written a new version that it seems to be more efficient. :) – freedev Aug 08 '16 at 23:20
  • @freedev I agree that an application shouldn't be order sensitive (except the order when a parameter appears multiple times), but my *preference* is to not modify the order. Anyway, your code could be easily changed to not modify the order. Please see my answer below, it's my attempt to reduce the solution to the smallest code size possible. However, mine modifies the first instance if there are multiple instances. – Adam Leggett Aug 09 '16 at 14:31
  • Calling the function multiple times with the same parameter and value will add the parameter multiple times to the url. I added a check, if the url already contains the parameter and value: if (url.indexOf(str) === -1) – Alig Nov 25 '16 at 09:18
  • 1
    The purpose of addParam function is indeed add multiple times a parameter, and maybe you should know you can pass same parameter even with same value multiple times. http://stackoverflow.com/questions/24059773/correct-way-to-pass-multiple-values-for-same-parameter-name-in-get-request – freedev Nov 25 '16 at 09:32
20

I have a 'class' that does this and here it is:

function QS(){
    this.qs = {};
    var s = location.search.replace( /^\?|#.*$/g, '' );
    if( s ) {
        var qsParts = s.split('&');
        var i, nv;
        for (i = 0; i < qsParts.length; i++) {
            nv = qsParts[i].split('=');
            this.qs[nv[0]] = nv[1];
        }
    }
}

QS.prototype.add = function( name, value ) {
    if( arguments.length == 1 && arguments[0].constructor == Object ) {
        this.addMany( arguments[0] );
        return;
    }
    this.qs[name] = value;
}

QS.prototype.addMany = function( newValues ) {
    for( nv in newValues ) {
        this.qs[nv] = newValues[nv];
    }
}

QS.prototype.remove = function( name ) {
    if( arguments.length == 1 && arguments[0].constructor == Array ) {
        this.removeMany( arguments[0] );
        return;
    }
    delete this.qs[name];
}

QS.prototype.removeMany = function( deleteNames ) {
    var i;
    for( i = 0; i < deleteNames.length; i++ ) {
        delete this.qs[deleteNames[i]];
    }
}

QS.prototype.getQueryString = function() {
    var nv, q = [];
    for( nv in this.qs ) {
        q[q.length] = nv+'='+this.qs[nv];
    }
    return q.join( '&' );
}

QS.prototype.toString = QS.prototype.getQueryString;

//examples
//instantiation
var qs = new QS;
alert( qs );

//add a sinle name/value
qs.add( 'new', 'true' );
alert( qs );

//add multiple key/values
qs.add( { x: 'X', y: 'Y' } );
alert( qs );

//remove single key
qs.remove( 'new' )
alert( qs );

//remove multiple keys
qs.remove( ['x', 'bogus'] )
alert( qs );

I have overridden the toString method so there is no need to call QS::getQueryString, you can use QS::toString or, as I have done in the examples just rely on the object being coerced into a string.

meouw
  • 40,162
  • 10
  • 48
  • 67
10

If you have a string with url that you want to decorate with a param, you could try this:

urlstring += ( urlstring.match( /[\?]/g ) ? '&' : '?' ) + 'param=value';

This means that ? will be the prefix of the parameter, but if you already have ? in urlstring, than & will be the prefix.

I would also recommend to do encodeURI( paramvariable ) if you didn't hardcoded parameter, but it is inside a paramvariable; or if you have funny characters in it.

See javascript URL Encoding for usage of the encodeURI function.

Saša
  • 3,178
  • 1
  • 20
  • 36
8

Sometime we see ? at the end URL, i found some solutions which generate results as file.php?&foo=bar. i came up with my own solution work perfectly as i want!

location.origin + location.pathname + location.search + (location.search=='' ? '?' : '&') + 'lang=ar'

Note: location.origin doesn't work in IE, here is its fix.

Mr.Shan0
  • 624
  • 7
  • 16
8

This is a simple way to add a query parameter:

const query = new URLSearchParams(window.location.search);
query.append("enabled", "true");

And that is it more here.

Please note the support specs.

Vadim Ovchinnikov
  • 10,848
  • 4
  • 43
  • 73
T04435
  • 7,493
  • 1
  • 41
  • 47
7

Following function will help you to add,update and delete parameters to or from URL.

//example1and

var myURL = '/search';

myURL = updateUrl(myURL,'location','california');
console.log('added location...' + myURL);
//added location.../search?location=california

myURL = updateUrl(myURL,'location','new york');
console.log('updated location...' + myURL);
//updated location.../search?location=new%20york

myURL = updateUrl(myURL,'location');
console.log('removed location...' + myURL);
//removed location.../search

//example2

var myURL = '/search?category=mobile';

myURL = updateUrl(myURL,'location','california');
console.log('added location...' + myURL);
//added location.../search?category=mobile&location=california

myURL = updateUrl(myURL,'location','new york');
console.log('updated location...' + myURL);
//updated location.../search?category=mobile&location=new%20york

myURL = updateUrl(myURL,'location');
console.log('removed location...' + myURL);
//removed location.../search?category=mobile

//example3

var myURL = '/search?location=texas';

myURL = updateUrl(myURL,'location','california');
console.log('added location...' + myURL);
//added location.../search?location=california

myURL = updateUrl(myURL,'location','new york');
console.log('updated location...' + myURL);
//updated location.../search?location=new%20york

myURL = updateUrl(myURL,'location');
console.log('removed location...' + myURL);
//removed location.../search

//example4

var myURL = '/search?category=mobile&location=texas';

myURL = updateUrl(myURL,'location','california');
console.log('added location...' + myURL);
//added location.../search?category=mobile&location=california

myURL = updateUrl(myURL,'location','new york');
console.log('updated location...' + myURL);
//updated location.../search?category=mobile&location=new%20york

myURL = updateUrl(myURL,'location');
console.log('removed location...' + myURL);
//removed location.../search?category=mobile

//example5

var myURL = 'https://example.com/search?location=texas#fragment';

myURL = updateUrl(myURL,'location','california');
console.log('added location...' + myURL);
//added location.../search?location=california#fragment

myURL = updateUrl(myURL,'location','new york');
console.log('updated location...' + myURL);
//updated location.../search?location=new%20york#fragment

myURL = updateUrl(myURL,'location');
console.log('removed location...' + myURL);
//removed location.../search#fragment

Here is the function.

function updateUrl(url,key,value){
      if(value!==undefined){
        value = encodeURI(value);
      }
      var hashIndex = url.indexOf("#")|0;
      if (hashIndex === -1) hashIndex = url.length|0;
      var urls = url.substring(0, hashIndex).split('?');
      var baseUrl = urls[0];
      var parameters = '';
      var outPara = {};
      if(urls.length>1){
          parameters = urls[1];
      }
      if(parameters!==''){
        parameters = parameters.split('&');
        for(k in parameters){
          var keyVal = parameters[k];
          keyVal = keyVal.split('=');
          var ekey = keyVal[0];
          var evalue = '';
          if(keyVal.length>1){
              evalue = keyVal[1];
          }
          outPara[ekey] = evalue;
        }
      }

      if(value!==undefined){
        outPara[key] = value;
      }else{
        delete outPara[key];
      }
      parameters = [];
      for(var k in outPara){
        parameters.push(k + '=' + outPara[k]);
      }

      var finalUrl = baseUrl;

      if(parameters.length>0){
        finalUrl += '?' + parameters.join('&'); 
      }

      return finalUrl + url.substring(hashIndex); 
  }
Jack Giffin
  • 3,108
  • 2
  • 26
  • 45
lingeshram
  • 542
  • 5
  • 11
6

Check out https://github.com/derek-watson/jsUri

Uri and query string manipulation in javascript.

This project incorporates the excellent parseUri regular expression library by Steven Levithan. You can safely parse URLs of all shapes and sizes, however invalid or hideous.

6

This was my own attempt, but I'll use the answer by annakata as it seems much cleaner:

function AddUrlParameter(sourceUrl, parameterName, parameterValue, replaceDuplicates)
{
    if ((sourceUrl == null) || (sourceUrl.length == 0)) sourceUrl = document.location.href;
    var urlParts = sourceUrl.split("?");
    var newQueryString = "";
    if (urlParts.length > 1)
    {
        var parameters = urlParts[1].split("&");
        for (var i=0; (i < parameters.length); i++)
        {
            var parameterParts = parameters[i].split("=");
            if (!(replaceDuplicates && parameterParts[0] == parameterName))
            {
                if (newQueryString == "")
                    newQueryString = "?";
                else
                    newQueryString += "&";
                newQueryString += parameterParts[0] + "=" + parameterParts[1];
            }
        }
    }
    if (newQueryString == "")
        newQueryString = "?";
    else
        newQueryString += "&";
    newQueryString += parameterName + "=" + parameterValue;

    return urlParts[0] + newQueryString;
}

Also, I found this jQuery plugin from another post on stackoverflow, and if you need more flexibility you could use that: http://plugins.jquery.com/project/query-object

I would think the code would be (haven't tested):

return $.query.parse(sourceUrl).set(parameterName, parameterValue).toString();
Lessan Vaezi
  • 5,257
  • 3
  • 23
  • 15
  • Thanks for sharing your code, Lessan. I've been using this and it's worked great! I've uploaded a gist of my own version, edited to be slightly more succinct and pass JSHint validation. https://gist.github.com/jonathanconway/02a183920506acd9890a – Jonathan Feb 01 '15 at 05:05
5

Try this.

// uses the URL class
function setParam(key, value) {
            let url = new URL(window.document.location);
            let params = new URLSearchParams(url.search.slice(1));

            if (params.has(key)) {
                params.set(key, value);
            }else {
                params.append(key, value);
            }
        }
Matěj Husák
  • 105
  • 1
  • 6
4

Adding to @Vianney's Answer https://stackoverflow.com/a/44160941/6609678

We can import the Built-in URL module in node as follows

const { URL } = require('url');

Example:

Terminal $ node
> const { URL } = require('url');
undefined
> let url = new URL('', 'http://localhost:1989/v3/orders');
undefined
> url.href
'http://localhost:1989/v3/orders'
> let fetchAll=true, timePeriod = 30, b2b=false;
undefined
> url.href
'http://localhost:1989/v3/orders'
>  url.searchParams.append('fetchAll', fetchAll);
undefined
>  url.searchParams.append('timePeriod', timePeriod);
undefined
>  url.searchParams.append('b2b', b2b);
undefined
> url.href
'http://localhost:1989/v3/orders?fetchAll=true&timePeriod=30&b2b=false'
> url.toString()
'http://localhost:1989/v3/orders?fetchAll=true&timePeriod=30&b2b=false'

Useful Links:

https://developer.mozilla.org/en-US/docs/Web/API/URL https://developer.mozilla.org/en/docs/Web/API/URLSearchParams

Jinxer Albatross
  • 1,109
  • 12
  • 17
4

It handles such URL's:

  • empty
  • doesn't have any parameters
  • already have some parameters
  • have ? at the end, but at the same time doesn't have any parameters

It doesn't handles such URL's:

  • with fragment identifier (i.e. hash, #)
  • if URL already have required query parameter (then there will be duplicate)

Works in:

  • Chrome 32+
  • Firefox 26+
  • Safari 7.1+
function appendQueryParameter(url, name, value) {
    if (url.length === 0) {
        return;
    }

    let rawURL = url;

    // URL with `?` at the end and without query parameters
    // leads to incorrect result.
    if (rawURL.charAt(rawURL.length - 1) === "?") {
        rawURL = rawURL.slice(0, rawURL.length - 1);
    }

    const parsedURL = new URL(rawURL);
    let parameters = parsedURL.search;

    parameters += (parameters.length === 0) ? "?" : "&";
    parameters = (parameters + name + "=" + value);

    return (parsedURL.origin + parsedURL.pathname + parameters);
}

Version with ES6 template strings.

Works in:

  • Chrome 41+
  • Firefox 32+
  • Safari 9.1+
function appendQueryParameter(url, name, value) {
    if (url.length === 0) {
        return;
    }

    let rawURL = url;

    // URL with `?` at the end and without query parameters
    // leads to incorrect result.
    if (rawURL.charAt(rawURL.length - 1) === "?") {
        rawURL = rawURL.slice(0, rawURL.length - 1);
    }

    const parsedURL = new URL(rawURL);
    let parameters = parsedURL.search;

    parameters += (parameters.length === 0) ? "?" : "&";
    parameters = `${parameters}${name}=${value}`;

    return `${parsedURL.origin}${parsedURL.pathname}${parameters}`;
}
Immersion
  • 409
  • 6
  • 16
3

Vianney Bajart's answer is correct; however, URL will only work if you have the complete URL with port, host, path and query:

new URL('http://server/myapp.php?id=10&enabled=true')

And URLSearchParams will only work if you pass only the query string:

new URLSearchParams('?id=10&enabled=true')

If you have an incomplete or relative URL and don't care for the base URL, you can just split by ? to get the query string and join later like this:

function setUrlParams(url, key, value) {
  url = url.split('?');
  usp = new URLSearchParams(url[1]);
  usp.set(key, value);
  url[1] = usp.toString();
  return url.join('?');
}

let url = 'myapp.php?id=10';
url = setUrlParams(url, 'enabled', true);  // url = 'myapp.php?id=10&enabled=true'
url = setUrlParams(url, 'id', 11);         // url = 'myapp.php?id=11&enabled=true'

Not compatible with Internet Explorer.

iau
  • 31
  • 2
  • If you use `var u = new URL(window.location), usp = u.searchParams;` you don't have to use any fancy string-splitting. – amphetamachine Mar 25 '20 at 14:08
  • While your solution will work for most things, it will mangle the URL if it has a question mark in a parameter value: `setUrlParams('https://example.com?foo=thing???&bar=baz', 'baz', 'qux') => "https://example.com?foo=thing&baz=qux???&bar=baz"` – amphetamachine Mar 25 '20 at 14:09
2

I would go with this small but complete library to handle urls in js:

https://github.com/Mikhus/jsurl

Joao Leme
  • 8,945
  • 3
  • 30
  • 46
2

This is what I use when it comes to some basic url param additions or updates on the server-side like Node.js.

CoffeScript:

###
    @method addUrlParam Adds parameter to a given url. If the parameter already exists in the url is being replaced.
    @param {string} url
    @param {string} key Parameter's key
    @param {string} value Parameter's value
    @returns {string} new url containing the parameter
###
addUrlParam = (url, key, value) ->
    newParam = key+"="+value
    result = url.replace(new RegExp('(&|\\?)' + key + '=[^\&|#]*'), '$1' + newParam)
    if result is url
        result = if url.indexOf('?') != -1 then url.split('?')[0] + '?' + newParam + '&' + url.split('?')[1]
    else if url.indexOf('#') != -1 then url.split('#')[0] + '?' + newParam + '#' + url.split('#')[1]
    else url + '?' + newParam
    return result

JavaScript:

function addUrlParam(url, key, value) {
    var newParam = key+"="+value;
    var result = url.replace(new RegExp("(&|\\?)"+key+"=[^\&|#]*"), '$1' + newParam);
    if (result === url) { 
        result = (url.indexOf("?") != -1 ? url.split("?")[0]+"?"+newParam+"&"+url.split("?")[1] 
           : (url.indexOf("#") != -1 ? url.split("#")[0]+"?"+newParam+"#"+ url.split("#")[1] 
              : url+'?'+newParam));
    }
    return result;
}

var url = "http://www.example.com?foo=bar&ciao=3&doom=5#hashme";
result1.innerHTML = addUrlParam(url, "ciao", "1");
<p id="result1"></p>
magiccrafter
  • 4,128
  • 1
  • 43
  • 38
2

Easiest solution, works if you have already a tag or not, and removes it automatically so it wont keep adding equal tags, have fun

function changeURL(tag)
{
if(window.location.href.indexOf("?") > -1) {
    if(window.location.href.indexOf("&"+tag) > -1){

        var url = window.location.href.replace("&"+tag,"")+"&"+tag;
    }
    else
    {
        var url = window.location.href+"&"+tag;
    }
}else{
    if(window.location.href.indexOf("?"+tag) > -1){

        var url = window.location.href.replace("?"+tag,"")+"?"+tag;
    }
    else
    {
        var url = window.location.href+"?"+tag;
    }
}
  window.location = url;
}

THEN

changeURL("i=updated");
Flavien Volken
  • 14,820
  • 9
  • 78
  • 105
Kuza Grave
  • 479
  • 5
  • 9
2

I like the answer of Mehmet Fatih Yıldız even he did not answer the whole question.

In the same line as his answer, I use this code:

"Its doesn't control parameter existence, and it doesn't change existing value. It adds your parameter to the end"

  /** add a parameter at the end of the URL. Manage '?'/'&', but not the existing parameters.
   *  does escape the value (but not the key)
   */
  function addParameterToURL(_url,_key,_value){
      var param = _key+'='+escape(_value);

      var sep = '&';
      if (_url.indexOf('?') < 0) {
        sep = '?';
      } else {
        var lastChar=_url.slice(-1);
        if (lastChar == '&') sep='';
        if (lastChar == '?') sep='';
      }
      _url += sep + param;

      return _url;
  }

and the tester:

  /*
  function addParameterToURL_TESTER_sub(_url,key,value){
    //log(_url);
    log(addParameterToURL(_url,key,value));
  }

  function addParameterToURL_TESTER(){
    log('-------------------');
    var _url ='www.google.com';
    addParameterToURL_TESTER_sub(_url,'key','value');
    addParameterToURL_TESTER_sub(_url,'key','Text Value');
    _url ='www.google.com?';
    addParameterToURL_TESTER_sub(_url,'key','value');
    _url ='www.google.com?A=B';
    addParameterToURL_TESTER_sub(_url,'key','value');
    _url ='www.google.com?A=B&';
    addParameterToURL_TESTER_sub(_url,'key','value');
    _url ='www.google.com?A=1&B=2';
    addParameterToURL_TESTER_sub(_url,'key','value');

  }//*/
Loda
  • 1,950
  • 2
  • 20
  • 37
1

If you're messing around with urls in links or somewhere else, you may have to take the hash into account as well. Here's a fairly simple to understand solution. Probably not the FASTEST since it uses a regex... but in 99.999% of cases, the difference really doesn't matter!

function addQueryParam( url, key, val ){
    var parts = url.match(/([^?#]+)(\?[^#]*)?(\#.*)?/);
    var url = parts[1];
    var qs = parts[2] || '';
    var hash = parts[3] || '';

    if ( !qs ) {
        return url + '?' + key + '=' + encodeURIComponent( val ) + hash;
    } else {
        var qs_parts = qs.substr(1).split("&");
        var i;
        for (i=0;i<qs_parts.length;i++) {
            var qs_pair = qs_parts[i].split("=");
            if ( qs_pair[0] == key ){
                qs_parts[ i ] = key + '=' + encodeURIComponent( val );
                break;
            }
        }
        if ( i == qs_parts.length ){
            qs_parts.push( key + '=' + encodeURIComponent( val ) );
        }
        return url + '?' + qs_parts.join('&') + hash;
    }
}
theozero
  • 562
  • 5
  • 8
  • Not sure why someone downvoted you. This is one of the more reliable solutions, although it's way more code than necessary. – Adam Leggett Aug 05 '16 at 20:33
1

The simplest solution I can think of is this method, which will return the modified URI. I feel like most of you are working way too hard.

function setParam(uri, key, val) {
    return uri
        .replace(new RegExp("([?&]"+key+"(?=[=&#]|$)[^#&]*|(?=#|$))"), "&"+key+"="+encodeURIComponent(val))
        .replace(/^([^?&]+)&/, "$1?");
}
Adam Leggett
  • 2,797
  • 23
  • 21
0

Here is what I do. Using my editParams() function, you can add, remove, or change any parameter, then use the built in replaceState() function to update the URL:

window.history.replaceState('object or string', 'Title', 'page.html' + editParams('enable', 'true'));


// background functions below:

// add/change/remove URL parameter
// use a value of false to remove parameter
// returns a url-style string
function editParams (key, value) {
  key = encodeURI(key);

  var params = getSearchParameters();

  if (Object.keys(params).length === 0) {
    if (value !== false)
      return '?' + key + '=' + encodeURI(value);
    else
      return '';
  }

  if (value !== false)
    params[key] = encodeURI(value);
  else
    delete params[key];

  if (Object.keys(params).length === 0)
    return '';

  return '?' + $.map(params, function (value, key) {
    return key + '=' + value;
  }).join('&');
}

// Get object/associative array of URL parameters
function getSearchParameters () {
  var prmstr = window.location.search.substr(1);
  return prmstr !== null && prmstr !== "" ? transformToAssocArray(prmstr) : {};
}

// convert parameters from url-style string to associative array
function transformToAssocArray (prmstr) {
  var params = {},
      prmarr = prmstr.split("&");

  for (var i = 0; i < prmarr.length; i++) {
    var tmparr = prmarr[i].split("=");
    params[tmparr[0]] = tmparr[1];
  }
  return params;
}
Bobb Fwed
  • 307
  • 2
  • 6
0

As best I can tell none of the above answers address the case where the query string contains parameters which are themselves an array and hence will appear more than once, e.g:

http://example.com?sizes[]=a&sizes[]=b

The following function is what I wrote to update document.location.search. It takes an array of key/value pair arrays as an argument and it will return a revised version of the latter which you can do whatever you'd like with. I'm using it like this:

var newParams = [
    ['test','123'],
    ['best','456'],
    ['sizes[]','XXL']
];
var newUrl = document.location.pathname + insertParams(newParams);
history.replaceState('', '', newUrl);

If the current url was:

http://example.com/index.php?test=replaceme&sizes[]=XL

This would get you

http://example.com/index.php?test=123&sizes[]=XL&sizes[]=XXL&best=456

Function

function insertParams(params) {
    var result;
    var ii = params.length;
    var queryString = document.location.search.substr(1);
    var kvps = queryString ? queryString.split('&') : [];
    var kvp;
    var skipParams = [];
    var i = kvps.length;
    while (i--) {
        kvp = kvps[i].split('=');
        if (kvp[0].slice(-2) != '[]') {
            var ii = params.length;
            while (ii--) {
                if (params[ii][0] == kvp[0]) {
                    kvp[1] = params[ii][1];
                    kvps[i] = kvp.join('=');
                    skipParams.push(ii);
                }
            }
        }
    }
    var ii = params.length;
    while (ii--) {
        if (skipParams.indexOf(ii) === -1) {
            kvps.push(params[ii].join('='));
        }
    }
    result = kvps.length ? '?' + kvps.join('&') : '';
    return result;
}
billynoah
  • 17,021
  • 9
  • 67
  • 90
0

Try
The regular expressions, so slow, thus:

var SetParamUrl = function(_k, _v) {// replace and add new parameters

    let arrParams = window.location.search !== '' ? decodeURIComponent(window.location.search.substr(1)).split('&').map(_v => _v.split('=')) : Array();
    let index = arrParams.findIndex((_v) => _v[0] === _k); 
    index = index !== -1 ? index : arrParams.length;
    _v === null ? arrParams = arrParams.filter((_v, _i) => _i != index) : arrParams[index] = [_k, _v];
    let _search = encodeURIComponent(arrParams.map(_v => _v.join('=')).join('&'));

    let newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + (arrParams.length > 0 ? '?' +  _search : ''); 

    // window.location = newurl; //reload 

    if (history.pushState) { // without reload  
        window.history.pushState({path:newurl}, null, newurl);
    }

};

var GetParamUrl = function(_k) {// get parameter by key

    let sPageURL = decodeURIComponent(window.location.search.substr(1)),
        sURLVariables = sPageURL.split('&').map(_v => _v.split('='));
    let _result = sURLVariables.find(_v => _v[0] === _k);
    return _result[1];

};

Example:

        // https://some.com/some_path
        GetParamUrl('cat');//undefined
        SetParamUrl('cat', "strData");// https://some.com/some_path?cat=strData
        GetParamUrl('cat');//strData
        SetParamUrl('sotr', "strDataSort");// https://some.com/some_path?cat=strData&sotr=strDataSort
        GetParamUrl('sotr');//strDataSort
        SetParamUrl('cat', "strDataTwo");// https://some.com/some_path?cat=strDataTwo&sotr=strDataSort
        GetParamUrl('cat');//strDataTwo
        //remove param
        SetParamUrl('cat', null);// https://some.com/some_path?sotr=strDataSort
amiron
  • 635
  • 9
  • 9
0

With the new achievements in JS here is how one can add query param to the URL:

var protocol = window.location.protocol,
    host = '//' + window.location.host,
    path = window.location.pathname,
    query = window.location.search;

var newUrl = protocol + host + path + query + (query ? '&' : '?') + 'param=1';

window.history.pushState({path:newUrl}, '' , newUrl);

Also see this possibility Moziila URLSearchParams.append()

Alliswell
  • 1,325
  • 18
  • 33
0

Ok here I compare Two functions, one made by myself (regExp) and another one made by (annakata).

Split array:

function insertParam(key, value)
{
    key = escape(key); value = escape(value);

    var kvp = document.location.search.substr(1).split('&');

    var i=kvp.length; var x; while(i--) 
    {
        x = kvp[i].split('=');

        if (x[0]==key)
        {
                x[1] = value;
                kvp[i] = x.join('=');
                break;
        }
    }

    if(i<0) {kvp[kvp.length] = [key,value].join('=');}

    //this will reload the page, it's likely better to store this until finished
    return "&"+kvp.join('&'); 
}

Regexp method:

function addParameter(param, value)
{
    var regexp = new RegExp("(\\?|\\&)" + param + "\\=([^\\&]*)(\\&|$)");
    if (regexp.test(document.location.search)) 
        return (document.location.search.toString().replace(regexp, function(a, b, c, d)
        {
                return (b + param + "=" + value + d);
        }));
    else 
        return document.location.search+ param + "=" + value;
}

Testing case:

time1=(new Date).getTime();
for (var i=0;i<10000;i++)
{
addParameter("test","test");
}
time2=(new Date).getTime();
for (var i=0;i<10000;i++)
{
insertParam("test","test");
}

time3=(new Date).getTime();

console.log((time2-time1)+" "+(time3-time2));

It seems that even with simplest solution (when regexp use only test and do not enter .replace function) it is still slower than spliting... Well. Regexp is kinda slow but... uhh...

  • as I mentioned, this is actually comparatively slow - and fwiw, document.location.search is clearer – annakata Jan 28 '09 at 12:18
0

This will work in all modern browsers.

function insertParam(key,value) {
      if (history.pushState) {
          var newurl = window.location.protocol + "//" + window.location.host + window.location.pathname + '?' +key+'='+value;
          window.history.pushState({path:newurl},'',newurl);
      }
    }
Prasobh.Kollattu
  • 1,331
  • 1
  • 17
  • 31
0

Reset all query string

var params = { params1:"val1", params2:"val2" };
let str = jQuery.param(params);

let uri = window.location.href.toString();
if (uri.indexOf("?") > 0)
   uri = uri.substring(0, uri.indexOf("?"));

console.log(uri+"?"+str);
//window.location.href = uri+"?"+str;
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Mahdi Bashirpour
  • 9,916
  • 5
  • 70
  • 101
0

There is a built-in function inside URL class that you can use it for easy dealing with query string key/value params:

const url = new URL(window.location.href);
// url.searchParams has several function, we just use `set` function
// to set a value, if you just want to append without replacing value
// let use `append` function

url.searchParams.set('key', 'value');

console.log(url.search) // <== '?key=value'

// if window.location.href has already some qs params this `set` function
// modify or append key/value in it

For more information about searchParams functions.

AmerllicA
  • 15,720
  • 11
  • 72
  • 103
-1
var MyApp = new Class();

MyApp.extend({
    utility: {
        queryStringHelper: function (url) {
            var originalUrl = url;
            var newUrl = url;
            var finalUrl;
            var insertParam = function (key, value) {
                key = escape(key);
                value = escape(value);

                //The previous post had the substr strat from 1 in stead of 0!!!
                var kvp = newUrl.substr(0).split('&');

                var i = kvp.length;
                var x;
                while (i--) {
                    x = kvp[i].split('=');

                    if (x[0] == key) {
                        x[1] = value;
                        kvp[i] = x.join('=');
                        break;
                    }
                }

                if (i < 0) {
                    kvp[kvp.length] = [key, value].join('=');
                }

                finalUrl = kvp.join('&');

                return finalUrl;
            };

            this.insertParameterToQueryString = insertParam;

            this.insertParams = function (keyValues) {
                for (var keyValue in keyValues[0]) {
                    var key = keyValue;
                    var value = keyValues[0][keyValue];
                    newUrl = insertParam(key, value);
                }
                return newUrl;
            };

            return this;
        }
    }
});
user1538467
  • 288
  • 2
  • 3
  • 10