391

With javascript how can I add a query string parameter to the url if not present or if it present, update the current value? I am using jquery for my client side development.

Liam
  • 22,818
  • 25
  • 93
  • 157
amateur
  • 40,217
  • 59
  • 181
  • 303
  • 1
    It seems like I've written the "parseQueryString" function in JavaScript about 100 times over my career. It's not hard. Key points, `String#split` takes a second parameter for max splits. jQuery's `map` will also be helpful. – jpsimons May 14 '11 at 00:52
  • This SO post also has many solutions http://stackoverflow.com/questions/1090948/change-url-parameters-with-jquery – Dilip Rajkumar Mar 07 '13 at 20:08
  • 1
    Some people are taking this question to mean "how to change the URL in the address bar" and others "how to change any URL variable" – PandaWood Jul 10 '16 at 11:55
  • possible duplicate of https://stackoverflow.com/questions/486896/adding-a-parameter-to-the-url-with-javascript – User Sep 27 '19 at 01:10

29 Answers29

494

I wrote the following function which accomplishes what I want to achieve:

function updateQueryStringParameter(uri, key, value) {
  var re = new RegExp("([?&])" + key + "=.*?(&|$)", "i");
  var separator = uri.indexOf('?') !== -1 ? "&" : "?";
  if (uri.match(re)) {
    return uri.replace(re, '$1' + key + "=" + value + '$2');
  }
  else {
    return uri + separator + key + "=" + value;
  }
}
Niyaz
  • 49,409
  • 55
  • 142
  • 181
amateur
  • 40,217
  • 59
  • 181
  • 303
  • 37
    This answer doesn't work when there is a hash in the URI - query strings must be placed before the hash, else they don't get sent to the server. http://jsfiddle.net/4yXzR/ – Greg Sep 20 '12 at 14:28
  • 8
    Limit separator variable scoping to local function by adding `var` just before separator declaration. – Andrea Salicetti Dec 11 '12 at 10:56
  • 2
    Nice! @greg: you are right - see my answer for a variant which should cope with hash tags – Adam Feb 22 '13 at 12:03
  • 4
    I think, you should add `value = encodeURIComponent(value);` in the first line, otherwise line breaks are not escaped correctly. – Felix Apr 10 '14 at 10:05
  • What is the logic behind the mixture of single and double quotes? – Andrew Aug 13 '14 at 02:01
  • @amateur will it replace key like names[0]='n1'? – Maheshkumar Sep 17 '14 at 08:28
  • 18
    This will take care of the hash as well: https://gist.github.com/niyazpk/f8ac616f181f6042d1e0 – Niyaz Oct 25 '14 at 14:07
  • Can you please create same regex for me to add the new parameters after # (not after ? mark) ? – Rahul Nov 04 '15 at 14:40
  • Maybe a nitpicky stylistic choice, but it might be better not to mutate the `uri` parameter to keep the function from surprising the programmer by mutating an object passed in as an argument, especially since you are explicitly returning the value for the new URI from the function, which makes it appear that you don't mean `uri` to be an "out" parameter. – josiah Apr 18 '16 at 02:26
  • The `key` must be escaped before creating the `RegExp`. You can use this: `function escapeRegExp(str) { return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); }`. This allows for parameters like `&filter[1]=john`. – Marius Bughiu Jul 03 '16 at 08:43
  • @rahul see my answer below – MaxZoom Sep 27 '16 at 14:07
  • 2
    Can someone explain why this requires the URL as a parameter? And why it returns the URL? Like, what is the use case here? Something like `window.location.href = updateQueryStringParameter(window.location.href, 'foo', 'bar')`? Why not just `updateQueryStringParameter('foo', 'bar')`? – JOATMON Apr 27 '17 at 17:22
  • This functions messes up anchors. a) The RegExp treats anchors as part of the value if the value is last in the URI. b) The else branch puts the anchor before the key-value-pair. – Rouven B. May 24 '17 at 11:11
  • Fails more test cases than it passes. test cases and complete function: https://stackoverflow.com/a/23529943/8385841 – Timar Ivo Batis Sep 28 '18 at 14:11
  • 1
    The final answer in the link given above in @Niyaz's [comment](https://stackoverflow.com/questions/5999118/how-can-i-add-or-update-a-query-string-parameter#comment41746301_6021027) is the ultimate answer – Anupam Oct 25 '18 at 09:59
  • You just saved hours of my day ! – Héctor León May 16 '19 at 10:57
192

I have expanded the solution and combined it with another that I found to replace/update/remove the querystring parameters based on the users input and taking the urls anchor into consideration.

Not supplying a value will remove the parameter, supplying one will add/update the parameter. If no URL is supplied, it will be grabbed from window.location

function UpdateQueryString(key, value, url) {
    if (!url) url = window.location.href;
    var re = new RegExp("([?&])" + key + "=.*?(&|#|$)(.*)", "gi"),
        hash;

    if (re.test(url)) {
        if (typeof value !== 'undefined' && value !== null) {
            return url.replace(re, '$1' + key + "=" + value + '$2$3');
        } 
        else {
            hash = url.split('#');
            url = hash[0].replace(re, '$1$3').replace(/(&|\?)$/, '');
            if (typeof hash[1] !== 'undefined' && hash[1] !== null) {
                url += '#' + hash[1];
            }
            return url;
        }
    }
    else {
        if (typeof value !== 'undefined' && value !== null) {
            var separator = url.indexOf('?') !== -1 ? '&' : '?';
            hash = url.split('#');
            url = hash[0] + separator + key + '=' + value;
            if (typeof hash[1] !== 'undefined' && hash[1] !== null) {
                url += '#' + hash[1];
            }
            return url;
        }
        else {
            return url;
        }
    }
}

Update

There was a bug when removing the first parameter in the querystring, I have reworked the regex and test to include a fix.

Second Update

As suggested by @JarónBarends - Tweak value check to check against undefined and null to allow setting 0 values

Third Update

There was a bug where removing a querystring variable directly before a hashtag would lose the hashtag symbol which has been fixed

Fourth Update

Thanks @rooby for pointing out a regex optimization in the first RegExp object. Set initial regex to ([?&]) due to issue with using (\?|&) found by @YonatanKarni

Fifth Update

Removing declaring hash var in if/else statement

Popnoodles
  • 27,674
  • 1
  • 40
  • 53
ellemayo
  • 3,218
  • 2
  • 18
  • 30
  • 5
    Just checking the 'truthiness' of `value` will cause this to remove variables from the querystring when you set their value to 0. so instead of `if (value) {}` you should use `if (typeOf value !== 'undefined' && value !== null) {}` – Jarón Barends Apr 16 '13 at 15:58
  • 1
    In the RegExp ([?|&]) should really be ([?&]) – rooby Jan 07 '14 at 15:37
  • Funny how that carried over from the original solution - could also use (\?|&) – ellemayo Jan 07 '14 at 16:17
  • 1
    getting a "invalid regular exception / invalid group" exception on regex creation in chrome Version 31.0.1650.63, solved by returning the beginning to be "([?&])" – Yonatan Karni Jan 15 '14 at 11:55
  • @YonatanKarni that's interesting, my quick test worked but I'll revert it to that until I have time to look into it thanks – ellemayo Jan 15 '14 at 15:07
  • 1
    Not that this matters except for me being OCD, but the variable `hash` is declared twice ;) – wlingke Jun 30 '14 at 02:30
  • @wlingke, that's true - but only within the cases that it's used (it's unused half the time) so only once within a flow of logic. Not sure where I stand on that :) – ellemayo Jul 01 '14 at 14:48
  • @ellemayo haha like I said - just being OCD since Javascript doesn't have blocks. – wlingke Jul 01 '14 at 18:18
  • you're declaring the hash var inside the first if, but using it in the "else" block, downvoting – knocte Nov 11 '14 at 20:33
  • @knocte thank you for the downvote - I was declaring it in the else block as well - "var separator, hash;" - but I've moved my declaration to the top of the function as per wlingke's original block scope suggestion – ellemayo Nov 12 '14 at 15:08
  • I don't see the declaration of "var hash", where is it? – knocte Nov 12 '14 at 15:22
  • oh, I guess you can do `var re = foo, hash;` ? it's not very clear/readable though, please put the hash var the first, before `re` – knocte Nov 12 '14 at 15:23
  • A linters worst nightmare :/ – cnp Jul 06 '15 at 23:24
  • The `key` must be escaped before creating the `RegExp`. You can use this: `function escapeRegExp(str) { return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); }`. This allows for parameters like `&filter[1]=john`. – Marius Bughiu Jul 03 '16 at 08:43
  • This is probably the most correct answer here, other than it doesn't escape values and it doesn't replace parameters that existed but were not assigned a value (`http://abc.def/?a&b&c`). It's also way more code than it needs to be. Check my solution at the bottom of the page. – Adam Leggett Aug 05 '16 at 18:11
  • It worked like a charm. It also worked on SharePoint REST API Search Url as well. Thank you – Durgesh Mar 03 '17 at 14:55
  • It doesn't work with arrays. For example it will append a new `arr[key]=value` to the end of URL even when an `arr[key]` parameter exists on the URL. So instead of updating the existing parameter, it will add a new one to the URL. Can you fix it please? – Hossein Jul 09 '18 at 08:23
  • fails for: http://example.com/? and http://example.com/?param Better: https://stackoverflow.com/a/23529943/8385841 – Timar Ivo Batis Sep 28 '18 at 14:14
182

Update (2020): URLSearchParams is now supported by all modern browsers.

The URLSearchParams utility can be useful for this in combination with window.location.search. For example:

if ('URLSearchParams' in window) {
    var searchParams = new URLSearchParams(window.location.search);
    searchParams.set("foo", "bar");
    window.location.search = searchParams.toString();
}

Now foo has been set to bar regardless of whether or not it already existed.

However, the above assignment to window.location.search will cause a page load, so if that's not desirable use the History API as follows:

if ('URLSearchParams' in window) {
    var searchParams = new URLSearchParams(window.location.search)
    searchParams.set("foo", "bar");
    var newRelativePathQuery = window.location.pathname + '?' + searchParams.toString();
    history.pushState(null, '', newRelativePathQuery);
}

Now you don't need to write your own regex or logic to handle the possible existence of query strings.

However, browser support is poor as it's currently experimental and only in use in recent versions of Chrome, Firefox, Safari, iOS Safari, Android Browser, Android Chrome and Opera. Use with a polyfill if you do decide to use it.

Abdalla Arbab
  • 1,111
  • 2
  • 19
  • 24
Anthony Manning-Franklin
  • 2,623
  • 1
  • 14
  • 21
  • polly fill, is not good, `Unable to set property '__URLSearchParams__:0.8503766759030615' of undefined or null reference` on ie11 you get that error. it's not a pollyfill if it doesn't work as a fallback. – Val Feb 08 '17 at 12:03
  • 9
    Update __2019__: Browser support is now good for most browsers except IE and some small mobile browsers. New pollyfill of ungap easily covers that: https://github.com/ungap/url-search-params – Flion Apr 30 '19 at 04:58
  • Perfect answer, however it doesnt handle usecase when hashtag is present in the url. Simple append of hash to the end of `newRelativePathQuery` does the trick: `var newRelativePathQuery = window.location.pathname + '?' + searchParams.toString() + window.location.hash;` – kudlohlavec Mar 13 '20 at 14:50
44

Based on @amateur's answer (and now incorporating the fix from @j_walker_dev comment), but taking into account the comment about hash tags in the url I use the following:

function updateQueryStringParameter(uri, key, value) {
  var re = new RegExp("([?&])" + key + "=.*?(&|#|$)", "i");
  if (uri.match(re)) {
    return uri.replace(re, '$1' + key + "=" + value + '$2');
  } else {
    var hash =  '';
    if( uri.indexOf('#') !== -1 ){
        hash = uri.replace(/.*#/, '#');
        uri = uri.replace(/#.*/, '');
    }
    var separator = uri.indexOf('?') !== -1 ? "&" : "?";    
    return uri + separator + key + "=" + value + hash;
  }
}

Edited to fix [?|&] in regex which should of course be [?&] as pointed out in the comments

Edit: Alternative version to support removing URL params as well. I have used value === undefined as the way to indicate removal. Could use value === false or even a separate input param as wanted.

function updateQueryStringParameter(uri, key, value) {
  var re = new RegExp("([?&])" + key + "=.*?(&|#|$)", "i");
  if( value === undefined ) {
    if (uri.match(re)) {
        return uri.replace(re, '$1$2');
    } else {
        return uri;
    }
  } else {
    if (uri.match(re)) {
        return uri.replace(re, '$1' + key + "=" + value + '$2');
    } else {
    var hash =  '';
    if( uri.indexOf('#') !== -1 ){
        hash = uri.replace(/.*#/, '#');
        uri = uri.replace(/#.*/, '');
    }
    var separator = uri.indexOf('?') !== -1 ? "&" : "?";    
    return uri + separator + key + "=" + value + hash;
  }
  }  
}

See it in action at https://jsfiddle.net/bp3tmuxh/1/

Adam
  • 6,361
  • 3
  • 34
  • 52
  • 2
    Much cleaner. FYI for angular ui-router users who can have "?" in the hash as well. Moving the `var separator` line to right above the return fixes a bug with "/app#/cool?fun=true". This would choose a "&" as the separator even though there are no real query string params yet. Only client ones. – j_walker_dev Jun 07 '15 at 10:28
  • 3
    As pointed out in comments on other answers, `[?|&]` should be just `[?&]` (otherwise will match `|`). – bonger Jan 07 '16 at 20:29
  • 1
    Yeah, `"([?|&])"` is not good. Please fix this as either `var re = new RegExp("(?|&)" + key + "=.*?(&|#|$)", "i");` or `var re = new RegExp("([?&])" + key + "=.*?(&|#|$)", "i");` (a nice extension in other ways!) – YakovL Oct 20 '16 at 11:11
  • ok, sorry, `var re = new RegExp("(?|&)" + key + "=.*?(&|#|$)", "i");` doesn't work, the second one does – YakovL Oct 20 '16 at 11:21
  • It seems like this version doesn't support removing a query string parameter by omitting the value. Am I right? – jkupczak Jan 03 '17 at 23:26
  • Not as such @jimmykup. Could adapat it to do so quite eaisly though – Adam Jan 04 '17 at 14:12
  • Thanks, great edit. In the JSFiddle if I repeatedly remove and add parameters eventually the URL ends up looking like this: `https://www.example.com/?&&&baz`And if I remove just the `foo` parameter I get this: `https://www.example.com/?&bar=2#baz` with both ? and & in there even though there's only one parameter. – jkupczak Jan 04 '17 at 16:50
  • Extra & symbols in the parameters should be harmless I think. They were when i checked $_REQUEST in PHP at least. – Adam Jan 04 '17 at 17:03
  • Unlike the others, this one works with even if the URL has hash. – serkan Nov 30 '17 at 08:25
20

Here is my library to do that: https://github.com/Mikhus/jsurl

var u = new Url;
u.query.param='value'; // adds or replaces the param
alert(u)
Mikhus
  • 1,049
  • 11
  • 8
14

I realize this question is old and has been answered to death, but here's my stab at it. I'm trying to reinvent the wheel here because I was using the currently accepted answer and the mishandling of URL fragments recently bit me in a project.

The function is below. It's quite long, but it was made to be as resilient as possible. I would love suggestions for shortening/improving it. I put together a small jsFiddle test suite for it (or other similar functions). If a function can pass every one of the tests there, I say it's probably good to go.

Update: I came across a cool function for using the DOM to parse URLs, so I incorporated that technique here. It makes the function shorter and more reliable. Props to the author of that function.

/**
 * Add or update a query string parameter. If no URI is given, we use the current
 * window.location.href value for the URI.
 * 
 * Based on the DOM URL parser described here:
 * http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
 *
 * @param   (string)    uri     Optional: The URI to add or update a parameter in
 * @param   (string)    key     The key to add or update
 * @param   (string)    value   The new value to set for key
 *
 * Tested on Chrome 34, Firefox 29, IE 7 and 11
 */
function update_query_string( uri, key, value ) {

    // Use window URL if no query string is provided
    if ( ! uri ) { uri = window.location.href; }

    // Create a dummy element to parse the URI with
    var a = document.createElement( 'a' ), 

        // match the key, optional square brackets, an equals sign or end of string, the optional value
        reg_ex = new RegExp( key + '((?:\\[[^\\]]*\\])?)(=|$)(.*)' ),

        // Setup some additional variables
        qs,
        qs_len,
        key_found = false;

    // Use the JS API to parse the URI 
    a.href = uri;

    // If the URI doesn't have a query string, add it and return
    if ( ! a.search ) {

        a.search = '?' + key + '=' + value;

        return a.href;
    }

    // Split the query string by ampersands
    qs = a.search.replace( /^\?/, '' ).split( /&(?:amp;)?/ );
    qs_len = qs.length; 

    // Loop through each query string part
    while ( qs_len > 0 ) {

        qs_len--;

        // Remove empty elements to prevent double ampersands
        if ( ! qs[qs_len] ) { qs.splice(qs_len, 1); continue; }

        // Check if the current part matches our key
        if ( reg_ex.test( qs[qs_len] ) ) {

            // Replace the current value
            qs[qs_len] = qs[qs_len].replace( reg_ex, key + '$1' ) + '=' + value;

            key_found = true;
        }
    }   

    // If we haven't replaced any occurrences above, add the new parameter and value
    if ( ! key_found ) { qs.push( key + '=' + value ); }

    // Set the new query string
    a.search = '?' + qs.join( '&' );

    return a.href;
}
Dominic P
  • 1,830
  • 1
  • 22
  • 41
  • 2
    This looks really good, solid test cases + using the DOM as URL parser. I did find two cases though: http://example.com/?param=val& => http://example.com/?param=val&&new=key --double & and http://example.com/team => http://example.com/team?new=key expected: team/?new=key some redirect /team?new=key to /team/ and the queries are lost. – Timar Ivo Batis Sep 28 '18 at 16:48
  • 1
    Thanks for the failing test case. I updated the fiddle. That first one is tough. Any ideas on how to fix the function for it? The second should be handled no problem and is already covered in the test suite. Maybe I don't understand you though. Feel free to fork the test fiddle to demonstrate what you're seeing. – Dominic P Sep 28 '18 at 22:01
  • I added some test cases i ran into and workarounds. I tried to use the DOM as much as possible. Primarily i needed this to also work for relative links within the same domain. http://jsfiddle.net/Timar/7sjrhbm3/ – Timar Ivo Batis Oct 31 '18 at 22:08
  • Why is it considered a good thing to use the DOM for something like this? – brad Feb 21 '19 at 16:58
  • 1
    @braed I like the approach because it leaves the heavy lifting to the browser. As you see from a lot of answers here, this problem is not as simple as it seems. There are A LOT of corner cases that a solution needs to cover. Most of them are covered for free when you leverage the DOM. – Dominic P Feb 21 '19 at 20:04
  • @DominicP I'd love some examples of those edge cases and how using the DOM covers them. I wouldn't have even considered creating a dummy element etc here. Can you point me in the direction of some reading material? – brad Feb 22 '19 at 10:05
  • 1
    @braed sure just take a look at the test suite I linked in the answer. A lot of the solutions here that don't rely on the DOM fail it because they don't account for all of the edge cases listed. As for reading, it might be instructive to look at the [URL module](https://nodejs.org/api/url.html) for node.js. It's not directly related, but it gives you an idea of some of the complexity involved in URL strings. – Dominic P Feb 22 '19 at 18:09
  • I think my misconception was that "using the DOM" was a common approach to solving issues in Javascript, but actually it's just useful here because anchor elements have their own attributes such as `hash` and `search`. – brad Feb 24 '19 at 19:50
12

If it's not set or want to update with a new value you can use:

window.location.search = 'param=value'; // or param=new_value

This is in simple Javascript, by the way.

EDIT

You may want to try using the jquery query-object plugin

window.location.search = jQuery.query.set("param", 5);

wal
  • 16,300
  • 7
  • 69
  • 104
tradyblix
  • 6,785
  • 3
  • 22
  • 28
11

window.location.search is read/write.

However - modifying the query string will redirect the page you're on and cause a refresh from the server.

If what you're attempting to do is maintain client side state (and potentially make it bookmark-able), you'll want to modify the URL hash instead of the query string, which keeps you on the same page (window.location.hash is read/write). This is how web sites like twitter.com do this.

You'll also want the back button to work, you'll have to bind javascript events to the hash change event, a good plugin for that is http://benalman.com/projects/jquery-hashchange-plugin/

Gal
  • 3,861
  • 1
  • 19
  • 20
  • 5
    Twitter no longer modifies hash! Hash is dead, welcome the **History API**! – Alba Mendez Nov 19 '12 at 18:46
  • it's far from dead. i think you are living in a magical dreamland where legacy browser compatibility is of no concern. this may be the case for you, but it's certainly not the case for the rest of us (or in fact the majority of us). perhaps *dying* is more appropriate... – AaronHS Jan 12 '15 at 15:27
  • 1
    One year later, It looks like the only semi-recent browser that does not support it is IE 9 – Douglas.Sesar Jan 06 '16 at 17:46
9

Here's my approach: The location.params() function (shown below) can be used as a getter or setter. Examples:

Given the URL is http://example.com/?foo=bar&baz#some-hash,

  1. location.params() will return an object with all the query parameters: {foo: 'bar', baz: true}.
  2. location.params('foo') will return 'bar'.
  3. location.params({foo: undefined, hello: 'world', test: true}) will change the URL to http://example.com/?baz&hello=world&test#some-hash.

Here is the params() function, which can optionally be assigned to the window.location object.

location.params = function(params) {
  var obj = {}, i, parts, len, key, value;

  if (typeof params === 'string') {
    value = location.search.match(new RegExp('[?&]' + params + '=?([^&]*)[&#$]?'));
    return value ? value[1] : undefined;
  }

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

  for (i = 0, len = _params.length; i < len; i++) {
    parts = _params[i].split('=');
    if (! parts[0]) {continue;}
    obj[parts[0]] = parts[1] || true;
  }

  if (typeof params !== 'object') {return obj;}

  for (key in params) {
    value = params[key];
    if (typeof value === 'undefined') {
      delete obj[key];
    } else {
      obj[key] = value;
    }
  }

  parts = [];
  for (key in obj) {
    parts.push(key + (obj[key] === true ? '' : '=' + obj[key]));
  }

  location.search = parts.join('&');
};
jake
  • 1,751
  • 2
  • 21
  • 29
7

This is my preference, and it covers the cases I can think of. Can anyone think of a way to reduce it to a single replace?

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

It's the end of 2020, thanks to modern javascript, node.js and browsers support, we can get out of 3rd-party library whirlpool (jquery, query-string etc.) and DRY ourselves.

Here are javascript(node.js) and typescript version for a function that adds or updates query params of given url:

Javascript

const getUriWithParam = (baseUrl, params) => {
  const Url = new URL(baseUrl);
  const urlParams = new URLSearchParams(Url.search);
  for (const key in params) {
    if (params[key] !== undefined) {
      urlParams.set(key, params[key]);
    }
  }
  Url.search = urlParams.toString();
  return Url.toString();
};

console.info('expected: https://example.com/?foo=bar');
console.log(getUriWithParam("https://example.com", {foo: "bar"}));

console.info('expected: https://example.com/slug?foo=bar#hash');
console.log(getUriWithParam("https://example.com/slug#hash", {foo: "bar"}));

console.info('expected: https://example.com/?bar=baz&foo=bar');
console.log(getUriWithParam("https://example.com?bar=baz", {foo: "bar"}));

console.info('expected: https://example.com/?foo=baz&bar=baz');
console.log(getUriWithParam("https://example.com?foo=bar&bar=baz", {foo: "baz"}));

Typescript


const getUriWithParam = (
  baseUrl: string,
  params: Record<string, any>
): string => {
  const Url = new URL(baseUrl);
  const urlParams: URLSearchParams = new URLSearchParams(Url.search);
  for (const key in params) {
    if (params[key] !== undefined) {
      urlParams.set(key, params[key]);
    }
  }
  Url.search = urlParams.toString();
  return Url.toString();
};

For React Native

URL is not implemented in React Native. So you have to install react-native-url-polyfill beforehand.

For object params

See the second solution in this answer

glinda93
  • 3,643
  • 2
  • 16
  • 39
5

I know this is quite old but i want to fires my working version in here.

function addOrUpdateUrlParam(uri, paramKey, paramVal) {
  var re = new RegExp("([?&])" + paramKey + "=[^&#]*", "i");
  if (re.test(uri)) {
    uri = uri.replace(re, '$1' + paramKey + "=" + paramVal);
  } else {
    var separator = /\?/.test(uri) ? "&" : "?";
    uri = uri + separator + paramKey + "=" + paramVal;
  }
  return uri;
}

jQuery(document).ready(function($) {
  $('#paramKey,#paramValue').on('change', function() {
    if ($('#paramKey').val() != "" && $('#paramValue').val() != "") {
      $('#uri').val(addOrUpdateUrlParam($('#uri').val(), $('#paramKey').val(), $('#paramValue').val()));
    }
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input style="width:100%" type="text" id="uri" value="http://www.example.com/text.php">
<label style="display:block;">paramKey
  <input type="text" id="paramKey">
</label>
<label style="display:block;">paramValue
  <input type="text" id="paramValue">
</label>

NOTE This is a modified version of @elreimundo

Paolo Falomo
  • 409
  • 3
  • 13
  • 1
    Tested with jsFiddle from Dominic P: FAIL :: http://example.com/? :: http://example.com/?&param=new Expected: http://example.com/?param=new FAIL :: http://example.com/?param :: http://example.com/?param&param=new Expected: http://example.com/?param=new FAIL :: http://example.com/?param=&param2 :: http://example.com/?param=new&param2 Expected: http://example.com/?param=new&param2 FAIL :: http://example.com/?param2=val&param[]=val :: http://example.com/?param2=val&param[]=val&param=new Expected: http://example.com/?param2=val&param[]=new – Timar Ivo Batis Sep 28 '18 at 14:05
3

It's so simple with URLSearchParams, supported in all modern browsers (caniuse).

let p = new URLSearchParams();
p.set("foo", "bar");
p.set("name", "Jack & Jill?");
console.log("http://example.com/?" + p.toString());

If you want to modify the existing URL, construct the object like this: new URLSearchParams(window.location.search) and assign the string to window.location.search.

Flimm
  • 97,949
  • 30
  • 201
  • 217
2

My take from here (compatible with "use strict"; does not really use jQuery):

function decodeURIParams(query) {
  if (query == null)
    query = window.location.search;
  if (query[0] == '?')
    query = query.substring(1);

  var params = query.split('&');
  var result = {};
  for (var i = 0; i < params.length; i++) {
    var param = params[i];
    var pos = param.indexOf('=');
    if (pos >= 0) {
        var key = decodeURIComponent(param.substring(0, pos));
        var val = decodeURIComponent(param.substring(pos + 1));
        result[key] = val;
    } else {
        var key = decodeURIComponent(param);
        result[key] = true;
    }
  }
  return result;
}

function encodeURIParams(params, addQuestionMark) {
  var pairs = [];
  for (var key in params) if (params.hasOwnProperty(key)) {
    var value = params[key];
    if (value != null) /* matches null and undefined */ {
      pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(value))
    }
  }
  if (pairs.length == 0)
    return '';
  return (addQuestionMark ? '?' : '') + pairs.join('&');
}

//// alternative to $.extend if not using jQuery:
// function mergeObjects(destination, source) {
//   for (var key in source) if (source.hasOwnProperty(key)) {
//     destination[key] = source[key];
//   }
//   return destination;
// }

function navigateWithURIParams(newParams) {
  window.location.search = encodeURIParams($.extend(decodeURIParams(), newParams), true);
}

Example usage:

// add/update parameters
navigateWithURIParams({ foo: 'bar', boz: 42 });

// remove parameter
navigateWithURIParams({ foo: null });

// submit the given form by adding/replacing URI parameters (with jQuery)
$('.filter-form').submit(function(e) {
  e.preventDefault();
  navigateWithURIParams(decodeURIParams($(this).serialize()));
});
Andrey Tarantsov
  • 8,554
  • 7
  • 51
  • 56
2

Based on the answer @ellemayo gave, I came up with the following solution that allows for disabling of the hash tag if desired:

function updateQueryString(key, value, options) {
    if (!options) options = {};

    var url = options.url || location.href;
    var re = new RegExp("([?&])" + key + "=.*?(&|#|$)(.*)", "gi"), hash;

    hash = url.split('#');
    url = hash[0];
    if (re.test(url)) {
        if (typeof value !== 'undefined' && value !== null) {
            url = url.replace(re, '$1' + key + "=" + value + '$2$3');
        } else {
            url = url.replace(re, '$1$3').replace(/(&|\?)$/, '');
        }
    } else if (typeof value !== 'undefined' && value !== null) {
        var separator = url.indexOf('?') !== -1 ? '&' : '?';
        url = url + separator + key + '=' + value;
    }

    if ((typeof options.hash === 'undefined' || options.hash) &&
        typeof hash[1] !== 'undefined' && hash[1] !== null)
        url += '#' + hash[1];
    return url;
}

Call it like this:

updateQueryString('foo', 'bar', {
    url: 'http://my.example.com#hash',
    hash: false
});

Results in:

http://my.example.com?foo=bar
RuubW
  • 546
  • 4
  • 17
  • Stylistic quibble: `typeof value !== 'undefined' && value !== null` is more explicit, but `value != null` means the same thing and is more concise. – eppsilon Mar 14 '18 at 21:17
2

Here is a shorter version that takes care of

  • query with or without a given parameter
  • query with multiple parameter values
  • query containing hash

Code:

var setQueryParameter = function(uri, key, value) {
  var re = new RegExp("([?&])("+ key + "=)[^&#]*", "g");
  if (uri.match(re)) 
    return uri.replace(re, '$1$2' + value);

  // need to add parameter to URI
  var paramString = (uri.indexOf('?') < 0 ? "?" : "&") + key + "=" + value;
  var hashIndex = uri.indexOf('#');
  if (hashIndex < 0)
    return uri + paramString;
  else
    return uri.substring(0, hashIndex) + paramString + uri.substring(hashIndex);
}

The regex description can be found here.

NOTE: This solution is based on @amateur answer, but with many improvements.

MaxZoom
  • 6,949
  • 5
  • 24
  • 41
2

Code that appends a list of parameters to an existing url using ES6 and jQuery:

class UrlBuilder {
    static appendParametersToUrl(baseUrl, listOfParams) {

        if (jQuery.isEmptyObject(listOfParams)) {
            return baseUrl;
        }

        const newParams = jQuery.param(listOfParams);

        let partsWithHash = baseUrl.split('#');
        let partsWithParams = partsWithHash[0].split('?');

        let previousParams = '?' + ((partsWithParams.length === 2) ? partsWithParams[1] + '&' : '');
        let previousHash = (partsWithHash.length === 2) ? '#' + partsWithHash[1] : '';

        return partsWithParams[0] + previousParams + newParams + previousHash;
    }
}

Where listOfParams is like

const listOfParams = {
    'name_1': 'value_1',
    'name_2': 'value_2',
    'name_N': 'value_N',
};

Example of Usage:

    UrlBuilder.appendParametersToUrl(urlBase, listOfParams);

Fast tests:

    url = 'http://hello.world';
    console.log('=> ', UrlParameters.appendParametersToUrl(url, null));
    // Output:  http://hello.world

    url = 'http://hello.world#h1';
    console.log('=> ', UrlParameters.appendParametersToUrl(url, null));
    // Output:  http://hello.world#h1

    url = 'http://hello.world';
    params = {'p1': 'v1', 'p2': 'v2'};
    console.log('=> ', UrlParameters.appendParametersToUrl(url, params));
    // Output: http://hello.world?p1=v1&p2=v2

    url = 'http://hello.world?p0=v0';
    params = {'p1': 'v1', 'p2': 'v2'};
    console.log('=> ', UrlParameters.appendParametersToUrl(url, params));
    // Output: http://hello.world?p0=v0&p1=v1&p2=v2

    url = 'http://hello.world#h1';
    params = {'p1': 'v1', 'p2': 'v2'};
    console.log('=> ', UrlParameters.appendParametersToUrl(url, params));
   // Output: http://hello.world?p1=v1&p2=v2#h1

    url = 'http://hello.world?p0=v0#h1';
    params = {'p1': 'v1', 'p2': 'v2'};
    console.log('=> ', UrlParameters.appendParametersToUrl(url, params));
    // Output: http://hello.world?p0=v0&p1=v1&p2=v2#h1
Samuel Vicent
  • 753
  • 6
  • 12
1

A different approach without using regular expressions. Supports 'hash' anchors at the end of the url as well as multiple question mark charcters (?). Should be slightly faster than the regular expression approach.

function setUrlParameter(url, key, value) {
  var parts = url.split("#", 2), anchor = parts.length > 1 ? "#" + parts[1] : '';
  var query = (url = parts[0]).split("?", 2);
  if (query.length === 1) 
    return url + "?" + key + "=" + value + anchor;

  for (var params = query[query.length - 1].split("&"), i = 0; i < params.length; i++)
    if (params[i].toLowerCase().startsWith(key.toLowerCase() + "="))
      return params[i] = key + "=" + value, query[query.length - 1] = params.join("&"), query.join("?") + anchor;

  return url + "&" + key + "=" + value + anchor
}
cwills
  • 1,978
  • 18
  • 17
1

Use this function to add, remove and modify query string parameter from URL based on jquery

/**
@param String url
@param object param {key: value} query parameter
*/
function modifyURLQuery(url, param){
    var value = {};

    var query = String(url).split('?');

    if (query[1]) {
        var part = query[1].split('&');

        for (i = 0; i < part.length; i++) {
            var data = part[i].split('=');

            if (data[0] && data[1]) {
                value[data[0]] = data[1];
            }
        }
    }

    value = $.extend(value, param);

    // Remove empty value
    for (i in value){
        if(!value[i]){
            delete value[i];
        }
    }

    // Return url with modified parameter
    if(value){
        return query[0] + '?' + $.param(value);
    } else {
        return query[0];
    }
}

Add new and modify existing parameter to url

var new_url = modifyURLQuery("http://google.com?foo=34", {foo: 50, bar: 45});
// Result: http://google.com?foo=50&bar=45

Remove existing

var new_url = modifyURLQuery("http://google.com?foo=50&bar=45", {bar: null});
// Result: http://google.com?foo=50
jay padaliya
  • 474
  • 4
  • 10
1

By using jQuery we can do like below

var query_object = $.query_string;
query_object["KEY"] = "VALUE";
var new_url = window.location.pathname + '?'+$.param(query_object)

In variable new_url we will have new query parameters.

Reference: http://api.jquery.com/jquery.param/

anjaneyulubatta505
  • 7,742
  • 1
  • 32
  • 50
0

To give an code example for modifying window.location.search as suggested by Gal and tradyblix:

var qs = window.location.search || "?";
var param = key + "=" + value; // remember to URI encode your parameters
if (qs.length > 1) {
    // more than just the question mark, so append with ampersand
    qs = qs + "&";
}
qs = qs + param;
window.location.search = qs;
Risadinha
  • 13,364
  • 2
  • 74
  • 80
0

Java script code to find a specific query string and replace its value *

('input.letter').click(function () {
                //0- prepare values
                var qsTargeted = 'letter=' + this.value; //"letter=A";
                var windowUrl = '';
                var qskey = qsTargeted.split('=')[0];
                var qsvalue = qsTargeted.split('=')[1];
                //1- get row url
                var originalURL = window.location.href;
                //2- get query string part, and url
                if (originalURL.split('?').length > 1) //qs is exists
                {
                    windowUrl = originalURL.split('?')[0];
                    var qs = originalURL.split('?')[1];
                    //3- get list of query strings
                    var qsArray = qs.split('&');
                    var flag = false;
                    //4- try to find query string key
                    for (var i = 0; i < qsArray.length; i++) {
                        if (qsArray[i].split('=').length > 0) {
                            if (qskey == qsArray[i].split('=')[0]) {
                                //exists key
                                qsArray[i] = qskey + '=' + qsvalue;
                                flag = true;
                                break;
                            }
                        }
                    }
                    if (!flag)//   //5- if exists modify,else add
                    {
                        qsArray.push(qsTargeted);
                    }
                    var finalQs = qsArray.join('&');
                    //6- prepare final url
                    window.location = windowUrl + '?' + finalQs;
                }
                else {
                    //6- prepare final url
                    //add query string
                    window.location = originalURL + '?' + qsTargeted;
                }
            })
        });
Mohamed.Abdo
  • 1,420
  • 16
  • 11
0

Here's an alternative method using the inbuilt properties of the anchor HTML element:

  • Handles multi-valued parameters.
  • No risk of modifying the # fragment, or anything other than the query string itself.
  • May be a little easier to read? But it is longer.

    var a = document.createElement('a'),

 getHrefWithUpdatedQueryString = function(param, value) {
     return updatedQueryString(window.location.href, param, value);
 },

 updatedQueryString = function(url, param, value) {
     /*
      A function which modifies the query string 
             by setting one parameter to a single value.

      Any other instances of parameter will be removed/replaced.
      */
     var fragment = encodeURIComponent(param) + 
                           '=' + encodeURIComponent(value);

     a.href = url;

     if (a.search.length === 0) {
  a.search = '?' + fragment;
     } else {
  var didReplace = false,
      // Remove leading '?'
      parts = a.search.substring(1)
  // Break into pieces
   .split('&'),

      reassemble = [],
      len = parts.length;

  for (var i = 0; i < len; i++) {
      
      var pieces = parts[i].split('=');
      if (pieces[0] === param) {
   if (!didReplace) {
       reassemble.push('&' + fragment);
       didReplace = true;
   }
      } else {
   reassemble.push(parts[i]);
      }
  }

  if (!didReplace) {
      reassemble.push('&' + fragment);
  }

  a.search = reassemble.join('&');
     }

     return a.href;
 };
GlennS
  • 4,490
  • 4
  • 23
  • 30
0

if you want to set multiple parameters at once:

function updateQueryStringParameters(uri, params) {
    for(key in params){
      var value = params[key],
          re = new RegExp("([?&])" + key + "=.*?(&|$)", "i"),
          separator = uri.indexOf('?') !== -1 ? "&" : "?";
      if (uri.match(re)) {
        uri = uri.replace(re, '$1' + key + "=" + value + '$2');
      }
      else {
        uri = uri + separator + key + "=" + value;
      }
    }
    return uri;
}

same function as @amateur's

if jslint gives you an error add this after the for loop

if(params.hasOwnProperty(key))
Rachid Oussanaa
  • 10,348
  • 14
  • 54
  • 83
0

There are a lot of awkward and unnecessarily complicated answers on this page. The highest rated one, @amateur's, is quite good, although it has a bit of unnecessary fluff in the RegExp. Here is a slightly more optimal solution with cleaner RegExp and a cleaner replace call:

function updateQueryStringParamsNoHash(uri, key, value) {
  var re = new RegExp("([?&])" + key + "=[^&]*", "i");
  return re.test(uri)
       ? uri.replace(re, '$1' + key + "=" + value)
       : uri + separator + key + "=" + value
  ;
}

As an added bonus, if uri is not a string, you won't get errors for trying to call match or replace on something that may not implement those methods.

And if you want to handle the case of a hash (and you've already done a check for properly formatted HTML), you can leverage the existing function instead of writing a new function containing the same logic:

function updateQueryStringParams(url, key, value) {
    var splitURL = url.split('#');
    var hash = splitURL[1];
    var uri = updateQueryStringParamsNoHash(splitURL[0]);
    return hash == null ? uri : uri + '#' + hash;
}

Or you can make some slight changes to @Adam's otherwise excellent answer:

function updateQueryStringParameter(uri, key, value) {
  var re = new RegExp("([?&])" + key + "=[^&#]*", "i");
  if (re.test(uri)) {
    return uri.replace(re, '$1' + key + "=" + value);
  } else {
    var matchData = uri.match(/^([^#]*)(#.*)?$/);
    var separator = /\?/.test(uri) ? "&" : "?";    
    return matchData[0] + separator + key + "=" + value + (matchData[1] || '');
  }
}
RAnders00
  • 4,419
  • 4
  • 30
  • 58
elreimundo
  • 5,516
  • 1
  • 11
  • 6
  • 2
    This is a missing bracket in the last function: var matchData = uri.match(/^([^#]*)(#.*)?$/ – Jammer Jan 19 '16 at 01:41
  • `separator` is not defined in `updateQueryStringParamsNoHash`. In `updateQueryStringParameter`, everything breaks down if the parameter you're replacing is not assigned a value (e.g. `http://abc.def/?a&b&c`). – Adam Leggett Aug 05 '16 at 17:56
0

This should serve the purpose:

function updateQueryString(url, key, value) {
    var arr =  url.split("#");
    var url = arr[0];
    var fragmentId = arr[1];
    var updatedQS = "";
    if (url.indexOf("?") == -1) {
        updatedQS = encodeURIComponent(key) + "=" + encodeURIComponent(value);
    }
    else {
        updatedQS = addOrModifyQS(url.substring(url.indexOf("?") + 1), key, value); 
    }
    url = url.substring(0, url.indexOf("?")) + "?" + updatedQS;
    if (typeof fragmentId !== 'undefined') {
        url = url + "#" + fragmentId;
    }
    return url;
}

function addOrModifyQS(queryStrings, key, value) {
    var oldQueryStrings = queryStrings.split("&");
    var newQueryStrings = new Array();
    var isNewKey = true;
    for (var i in oldQueryStrings) {
        var currItem = oldQueryStrings[i];
        var searchKey = key + "=";
        if (currItem.indexOf(searchKey) != -1) {
            currItem = encodeURIComponent(key) + "=" + encodeURIComponent(value);
            isNewKey = false;
        }
        newQueryStrings.push(currItem);
    }
    if (isNewKey) {
        newQueryStrings.push(encodeURIComponent(key) + "=" + encodeURIComponent(value));
    }
    return newQueryStrings.join("&");
}   
mmuzahid
  • 2,124
  • 20
  • 37
0

Here's my slightly different approach to this, written as an excercise

function addOrChangeParameters( url, params )
{
  let splitParams = {};
  let splitPath = (/(.*)[?](.*)/).exec(url);
  if ( splitPath && splitPath[2] )
    splitPath[2].split("&").forEach( k => { let d = k.split("="); splitParams[d[0]] = d[1]; } );
  let newParams = Object.assign( splitParams, params );
  let finalParams = Object.keys(newParams).map( (a) => a+"="+newParams[a] ).join("&");
  return splitPath ? (splitPath[1] + "?" + finalParams) : (url + "?" + finalParams);
}

usage:

const url = "http://testing.com/path?empty&value1=test&id=3";

addOrChangeParameters( url, {value1:1, empty:"empty", new:0} )

"http://testing.com/path?empty=empty&value1=1&id=3&new=0"
astu
  • 11
0

This answer is just a small tweak of ellemayo's answer. It will automatically update the URL instead of just returning the updated string.

function _updateQueryString(key, value, url) {
    if (!url) url = window.location.href;

    let updated = ''
    var re = new RegExp("([?&])" + key + "=.*?(&|#|$)(.*)", "gi"),
        hash;

    if (re.test(url)) {
        if (typeof value !== 'undefined' && value !== null) {
            updated = url.replace(re, '$1' + key + "=" + value + '$2$3');
        } 
        else {
            hash = url.split('#');
            url = hash[0].replace(re, '$1$3').replace(/(&|\?)$/, '');
            if (typeof hash[1] !== 'undefined' && hash[1] !== null) {
                url += '#' + hash[1];
            }
            updated = url;
        }
    }
    else {
        if (typeof value !== 'undefined' && value !== null) {
            var separator = url.indexOf('?') !== -1 ? '&' : '?';
            hash = url.split('#');
            url = hash[0] + separator + key + '=' + value;
            if (typeof hash[1] !== 'undefined' && hash[1] !== null) {
                url += '#' + hash[1];
            }
            updated = url;
        }
        else {
            updated = url;
        }
    }

    window.history.replaceState({ path: updated }, '', updated);
}
Diego Fortes
  • 4,742
  • 2
  • 17
  • 26
-1

Yeah I had an issue where my querystring would overflow and duplicate, but this was due to my own sluggishness. so I played a bit and worked up some js jquery(actualy sizzle) and C# magick.

So i just realized that after the server has done with the passed values, the values doesn't matter anymore, there is no reuse, if the client wanted to do the same thing evidently it will always be a new request, even if its the same parameters being passed. And thats all clientside, so some caching/cookies etc could be cool in that regards.

JS:

$(document).ready(function () {
            $('#ser').click(function () {
                SerializeIT();
            });
            function SerializeIT() {
                var baseUrl = "";
                baseUrl = getBaseUrlFromBrowserUrl(window.location.toString());
                var myQueryString = "";
                funkyMethodChangingStuff(); //whatever else before serializing and creating the querystring
                myQueryString = $('#fr2').serialize();
                window.location.replace(baseUrl + "?" + myQueryString);
            }
            function getBaseUrlFromBrowserUrl(szurl) {
                return szurl.split("?")[0];
            } 
            function funkyMethodChangingStuff(){
               //do stuff to whatever is in fr2
            }
        });

HTML:

<div id="fr2">
   <input type="text" name="qURL" value="http://somewhere.com" />
   <input type="text" name="qSPart" value="someSearchPattern" />
</div>
<button id="ser">Serialize! and go play with the server.</button>

C#:

    using System.Web;
    using System.Text;
    using System.Collections.Specialized;

    public partial class SomeCoolWebApp : System.Web.UI.Page
    {
        string weburl = string.Empty;
        string partName = string.Empty;

        protected void Page_Load(object sender, EventArgs e)
        {
            string loadurl = HttpContext.Current.Request.RawUrl;
            string querySZ = null;
            int isQuery = loadurl.IndexOf('?');
            if (isQuery == -1) { 
                //If There Was no Query
            }
            else if (isQuery >= 1) {
                querySZ = (isQuery < loadurl.Length - 1) ? loadurl.Substring(isQuery + 1) : string.Empty;
                string[] getSingleQuery = querySZ.Split('?');
                querySZ = getSingleQuery[0];

                NameValueCollection qs = null;
                qs = HttpUtility.ParseQueryString(querySZ);

                weburl = qs["qURL"];
                partName = qs["qSPart"];
                //call some great method thisPageRocks(weburl,partName); or whatever.
          }
      }
  }

Okay criticism is welcome (this was a nightly concoction so feel free to note adjustments). If this helped at all, thumb it up, Happy Coding.

No duplicates, each request as unique as you modified it, and due to how this is structured,easy to add more queries dynamicaly from wthin the dom.

LokizFenrir
  • 356
  • 3
  • 9