vote up 1 vote down
star

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.

flag
add comment

7 Answers:

vote up 4 vote down
check

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;
}
link|flag
thanks again. see lessanvaezi.com/wp-content/uploads/… for a basic comparison of the methods – Lessan Vaezi Jan 28 at 20:13
add comment
vote up 1 vote down

I had a similar scenario once and I found this article by Peter Bromberg very helpful :

link|flag
add comment
vote up 1 vote down

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.

link|flag
add comment
vote up 1 vote down

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();
link|flag
add comment
vote up 1 vote down

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

link|flag
as I mentioned, this is actually comparatively slow - and fwiw, document.location.search is clearer – annakata Jan 28 at 12:18
add comment
vote up 0 vote down

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.

link|flag
add comment
vote up 0 vote down

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.

link|flag
add comment

Your Answer:

Get an OpenID
or

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