Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

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.

share|improve this question
Have you searched for javascript url parsers ? You could make your own, splitting on every &-character, but it's probably easier just to use existing code. – csl Jan 28 '09 at 8:38
I had a similar scenario once and I found this article by Peter Bromberg very helpful : – Cerebrus Jan 28 '09 at 9:01

13 Answers

up vote 53 down vote accepted

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

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
    document.location.search = kvp.join('&'); 
}

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 = escape(key); value = escape(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;
}
share|improve this answer
2  
thanks again. see 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 9:50
4  
Using escape() to escape URL parameters is wrong. It breaks for values with "+" in them. You should be using encodeURIComponent instead. Full discussion: xkr.us/articles/javascript/encode-compare – Darwin Jun 9 '11 at 17:52
2  
I am calling this function and the page is reloading in infinite loop. Please help! – iSumitG Jul 24 '11 at 16:34
1  
What about hashtags? – skerit Aug 5 '11 at 8:55
show 5 more comments

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('&');
        }
    }
share|improve this answer
Needs a question mark before the key. Also you used double-quotes which is inconsistent with annakata's code. – Muhd Dec 1 '11 at 2:47
Edited to address my concerns. – Muhd Dec 1 '11 at 2:48
Nice! seems to work just fine! – Roy Toledo Aug 23 '12 at 12:49

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.

share|improve this answer

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;
}
share|improve this answer
+1: answer the title of the question (but not the question). still... it is what I need. – Loda Aug 31 '11 at 10:07
1  
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
@kanzure this thing looks evil as hell, but it's exactly what I wanted. Thanks. – Chad von Nau Sep 2 '12 at 2:44

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');
share|improve this answer
thanks for this – Roch Delsalle Aug 4 '10 at 14:37
1  
+1 I like how you can specify something other than document.location.search – Muhd Nov 29 '11 at 1:06
1  
Except that '$1' doesn't work. – Muhd Dec 1 '11 at 1:08

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();
share|improve this answer

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...

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

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');

  }//*/
share|improve this answer
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;
        }
    }
});
share|improve this answer

May be this can be another good solution:

function addParam(url, param, value) {
     var a = document.createElement('a');
     a.href = url;
     a.search += a.search.substring(0,1) == "?" ? "&" : "?";
     a.search += encodeURIComponent(param);
     if (value)
         a.search += "=" + encodeURIComponent(value);
     return a.href;
}

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

http://jsfiddle.net/bknE4/3/

share|improve this answer

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;
    }
}
share|improve this answer

Check out https://code.google.com/p/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.

share|improve this answer

I'll have a go. I'd do something like this:

function constructQuery(newkey, newvalue) {
	// the url will be split into three pieces
	var stem = window.location.href; 
	var query = "";
	var anchor = "";

	// split off the anchor
	var anchorindex = stem.lastIndexOf("#");
	if(anchorindex != -1) {
		anchor = stem.substring(anchorindex);
		stem = stem.substring(0, anchorindex);
	}

	// split off the query
	var queryindex = stem.lastIndexOf("?");
	if(queryindex != -1) {
		query = stem.substring(queryindex+1);
		stem = stem.substring(0, queryindex+1);
	}
	else{ stem += "?"; }

	// rewrite the query
	if(query != "") {
		var parameters = query.split("&");
		var newquery = "";
		for(int i = 0; i < parameters.length; ++i) {
			var parameter = parameters[i].split("=");
			if(parameter[0] == newkey) { continue; }
			if(newquery.length > 0) { newquery += "&"; }
			newquery += parameter;
		}
		query = newquery + "&" + newkey + "=" + newvalue;
	}

	// recombine the three pieces
	return stem + query + anchor;
}

I made up this code just then so I hope I've thought through everything but I might've missed something. I don't know if it even compiles, but at least you get the idea.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.