0

I have a couple of menu's that add a variable to the current link uppon click. Here is an example:

<select onChange="window.location.href+=this.value">
  <option value="&numb=1">1</option>
  <option value="&numb=2">2</option>
  <option value="&numb=3">3</option>
</select>

<select onChange="window.location.href+=this.value">
  <option value="&cord=x">x</option>
  <option value="&cord=y">y</option>
  <option value="&cord=z">z</option>
</select>

My problem is then, if I choose "y" 2 times, it adds "&cord=y" 2 times. Instead I want it to replace the current value from that menu. So if "&cord=x" is allready present, it would then just change it to "&cord=y" instead of adding a new variable to the link. Ofcourse, if I choose one from the &numb menu, it shouldn't replace one from the &cord menu.

Can this be done? If yes, then how?

EDIT: Here is another example. If I have the url "www.google.com?cat=p&comp=x&type=1" and I choose "&comp=3" in my select box, It will then replace the current &comp with the new. If &comp is not set, it will just add &comp=3 (or whatever I chose) to the url.

3
  • What are you trying to do? This is probably not the best way to do it. Commented Apr 26, 2015 at 14:08
  • There was a mistake in my syntax/fiddle and I just corrected it Commented Apr 26, 2015 at 14:10
  • yeah , it will happen because you just changed the href . I agree with Ed but if you want to do it this way, you may try : <select onChange="window.location.search = <static thing> + this.value"> Commented Apr 26, 2015 at 14:15

6 Answers 6

1

These functions should let you parse and edit the URL parameters:

function splitObj(str, rowSplit, columnSplit) {
    var obj = {};
    var rows = str.split(rowSplit);
    for (var i = 0; i < rows.length; i++) {
        var kv = rows[i].split(columnSplit);
        if (kv.length === 1) {
            obj[kv[0]] = null;            
        } else {
            obj[kv[0]] = kv[1];
        }
    }
    return obj;
}

function joinObj(obj, rowSplit, columnSplit) {
    var rows = [];
    for (var name in obj) {
        if (name[obj] === null) {
            rows.push(name);            
        } else {
            rows.push(name + columnSplit + obj[name]);
        }
    }
    return rows.join(rowSplit);
}

function setUrlParam(name, value) {
    var parts = window.location.href.split('?');
    var urlbase = parts[0];
    var params = {};
    if (parts.length > 1) {
        params = splitObj(parts[1], '&', '=');
    }
    params[encodeURIComponent(name)] = encodeURIComponent(value);
    window.location.href = urlbase + '?' + joinObj(params, '&', '=');
}

function changeURL(elem) {
    var kv = elem.value.slice(1).split('=');
    setUrlParam(kv[0], kv[1]);
}

Then you can do:

<select id="select" onChange="changeURL(this);">
    <option value="&cord=x">x</option>
    <option value="&cord=y">y</option>
    <option value="&cord=z">z</option>
</select>

UPDATE:

You can make it cut out the splitObj and joinObj at the cost of readability.

function setUrlParam(name, value) {
    var parts = window.location.href.split('?'), params = {};
    if (parts.length > 1)
        parts[1].split('&').forEach(function(x){ 
            var p = x.split('='); 
            params[p[0]] = (p.length > 1) ? p[1] : null; 
        });
    params[encodeURIComponent(name)] = encodeURIComponent(value);
    window.location.href = parts[0] + '?' + Object.keys(params).map(function(x){ 
        return (params[x] === null) ? x : (x + '=' + params[x]); 
    }).join('&');
}

function changeURL(elem) {
    var kv = elem.value.slice(1).split('=');
    setUrlParam(kv[0], kv[1]);
}
Sign up to request clarification or add additional context in comments.

5 Comments

Just tested it, and it dosen't do anything to the url :/
Perfect! :) Works like a charm. Not to be picky or anything, but is it possible to shrink it a bit? :)
You can shrink it by putting it through a minifier. What exactly are you trying to shrink?
Just wanted it a bit more compact thats all :)
I was able to trim it down a bit. You can also remove the ternary ? : operations if you know all parameters will be set, but it won't always be safe otherwise.
0

You would add an if statement so that it checks if there is already a value in the window. By doing this, you would replace the value with the current one.

Comments

0

Change window.location.href to window.location.origin

<select onChange="window.location.href=window.location.origin+this.value">

fiddle

1 Comment

Not working correctly. Going back to root instead of adding the variable to the existing link.
0

EDIT Go for something like this: http://jsfiddle.net/63s8eb70/5/

<select onChange="makeUrl()">
  <option value="?numb=1">1</option>
  <option value="?numb=2">2</option>
  <option value="?numb=3">3</option>
</select>

<select id="select" onChange="makeUrl();">
    <option value="&cord=x">x</option>
    <option value="&cord=y">y</option>
    <option value="&cord=z">z</option>
</select>

<br><br>

<div id="cu"></div>

JS

var current_Url = "";

function makeUrl() {

    var base = window.location.origin;

    var e = document.getElementById("select");
    var val = e.options[e.selectedIndex].value;

    if (current_Url === "") {
        current_Url = base + val;
        document.getElementById('cu').innerHTML = current_Url;
        //Comment out the next line on you actual site
        //document.location.href = current_Url; 
    } 
    else {
        current_Url += val;
        document.getElementById('cu').innerHTML = current_Url;
        //Comment out the next line on you actual site
        //document.location.href = current_Url; 
    }
}

8 Comments

Not changing anything
Do you know how to use the console?
Ok see this fiddle, it has a div that will hold the currenURl and display changes made to it :)
Thanks, but you missed the point of my question. When you select "X" for instance, javascript must check the link to see if &cord is already set. If it is, it will replace it with &cord=x. If not, it will just set &cord=x.
Ah ok I see, sorry still missed it :) well that is a different problem indeed and harder to solve...
|
0

This function takes the a parameter and a value and either adds it to the URL or updates the parameter if it already exists.

function urlQueryString(parameter, value) {
    var url = window.location.href;
    var regex = new RegExp("([?&])" + parameter + "=.*?(&|#|$)(.*)", "gi"),
        hash;

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

4 Comments

Im not into using jQuery.
Please avoid giving jQuery answers when OP is not asking explicitly for jQuery solution.
Alright, updated my answer for a solution in plain JS
Gotcha. Updated once again. This code will take a parameter name and value and will either add it to the url or update the existing one
0

It would be wise to give your input element a name attribute indicating the name of the parameter you're trying to change so you don't repeat the numb= part and coord= part over and over. Consider something like this, which lets you parameterize the name of the query key you're trying to change:

<select name="numb" onChange="updateSearch(event)">
  <option value="1">1</option>
  <option value="2">2</option>
  <option value="3">3</option>
</select>

<select name="coord" onChange="updateSearch(event)">
  <option value="x">x</option>
  <option value="y">y</option>
  <option value="z">z</option>
</select>

That way you can make as many of these input element you'd like and use the same event handler for the onchange.

The corresponding javascript could look like this:

function updateSearch(event) {
    var param = event.target.name;
    var value = event.target.value;
    var params = parseQuery(window.location.search);

    params[param] = value;

    window.location.search = buildQuery(params);
}

function parseQuery(querystring) {
    if (!querystring) { return {}; }
    var pairs = querystring.replace(/^\?/, '').split('&');
    var params = {};
    var pair;
    var i;

    for (i = 0; i < pairs.length; i++) {
        pair = pairs[i].split('=');
        params[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
    }
    return params;
}

function buildQuery(params) {
    var pairs = [];
    var key;
    for (key in params) { 
        if (!params.hasOwnProperty(key)) { continue; }
        pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(params[key]));
    }
    return pairs.join('&');
}

Some of the verbosity here is dealing with a string of serialized parameters in your URL safely and without using a lot of string manipulation. Consider those functions reusable for any instances you want to fetch or set some query parameters from the client-side.

Here's a jsFiddle: https://jsfiddle.net/8fftmwzn/20/

This implementation does not (of course) handle settings the inputs to what's already in your URL querystring. That's a separate challenge.

1 Comment

Thank you for your input, but I already found and accepted a working answer :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.