最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Toggle query string variables - Stack Overflow

programmeradmin2浏览0评论

I've been banging my head over this.

Using jquery or javascript, how can I toggle variables & values and then rebuild the query string? For example, my starting URL is:

;size=small,medium,large&shape=round

Then, if the user clicks a button labeled "red", I want to end up with:

,medium,large&shape=round //color is removed

Then, if the user clicks "red" again, I want to end up with:

,medium,large&shape=round&color=red //color is added back

Then, if the user clicks a button labeled "medium", I want to end up with:

,large&shape=round&color=red //medium is removed from list

Then, if the user clicks the labeled "medium" again, I want to end up with:

,large,medium&shape=round&color=red //medium added back

It doesn't really matter what order the variable are in; I've just been tacking them to the end.

I've been banging my head over this.

Using jquery or javascript, how can I toggle variables & values and then rebuild the query string? For example, my starting URL is:

http://example.com?color=red&size=small,medium,large&shape=round

Then, if the user clicks a button labeled "red", I want to end up with:

http://example.com?size=small,medium,large&shape=round //color is removed

Then, if the user clicks "red" again, I want to end up with:

http://example.com?size=small,medium,large&shape=round&color=red //color is added back

Then, if the user clicks a button labeled "medium", I want to end up with:

http://example.com?size=small,large&shape=round&color=red //medium is removed from list

Then, if the user clicks the labeled "medium" again, I want to end up with:

http://example.com?size=small,large,medium&shape=round&color=red //medium added back

It doesn't really matter what order the variable are in; I've just been tacking them to the end.

Share Improve this question asked Oct 29, 2011 at 6:38 xd3vxd3v 1591 silver badge10 bronze badges 5
  • Have a look here stackoverflow.com/questions/2053157/… – mplungjan Commented Oct 29, 2011 at 6:46
  • Doesn't really handle multiple values in a single variable, but I can probably piece it together. Thanks for the find. – xd3v Commented Oct 29, 2011 at 6:56
  • Sorry I did not have time to make a generic thing for you – mplungjan Commented Oct 29, 2011 at 10:10
  • this is very interested question, thank you! – Anatoly Commented Oct 29, 2011 at 12:39
  • Gotta say people... every one of these solutions rocked! – xd3v Commented Nov 3, 2011 at 6:22
Add a comment  | 

6 Answers 6

Reset to default 7
function toggle(url, key, val) {
    var out = [],
        upd = '',
        rm = "([&?])" + key + "=([^&]*?,)?" + val + "(,.*?)?(&.*?)?$",
        ad = key + "=",
        rmrplr = function(url, p1, p2, p3, p4) {
            if (p2) {
                if (p3) out.push(p1, key, '=', p2, p3.substr(1));
                else out.push(p1, key, '=', p2.substr(0, p2.length - 1));
            } else {
                if (p3) out.push(p1, key, '=', p3.substr(1));
                else out.push(p1);
            }
            if (p4) out.push(p4);
            return out.join('').replace(/([&?])&/, '$1').replace(/[&?]$/, ''); //<!2
        },
        adrplr = function(s) {
            return s + val + ',';
        };
    if ((upd = url.replace(new RegExp(rm), rmrplr)) != url) return upd;
    if ((upd = url.replace(new RegExp(ad), adrplr)) != url) return upd;
    return url + (/\?.+/.test(url) ? '&' : '?') + key + '=' + val; //<!1
}

params self described enough, hope this help.

!1: changed from ...? '&' : '' to ... ? '&' : '?'

!2: changed from .replace('?&','?')... to .replace(/([&?]&)/,'$1')...

http://jsfiddle.net/ycw7788/Abxj8/

I have written a function, which efficiently results in the expected behaviour, without use of any libraries or frameworks. A dynamic demo can be found at this fiddle: http://jsfiddle.net/w8D2G/1/

Documentation

Definitions:
The shown example values will be used at the Usage section, below
  -   Haystack - The string to search in (default = query string. e.g: ?size=small,medium)
  -   Needle - The key to search for. Example: size
  -   Value - The value to replace/add. Example: medium.

Usage (Example: input > output):

  1. qs_replace(needle, value)
    If value exists, remove: ?size=small,medium > ?size=small
    If value not exists, add: ?size=small > size=small,medium
  2. qs_replace(needle, options)     Object options. Recognised options:
    • find
      String. Returns true if the value exists, false otherwise.
    • add, remove or toggle
      String. Add/remove the given value to/from needle. If remove is used, and the value was the only value, needle is also removed. A value won't be added if it already exists.
    • ignorecase
      Ignore case while looking for the search terms (needle, add, remove or find).
    • separator
      Specify a separator to separate values of needle. Default to comma (,).

Note :   A different value for String haystack can also be defined, by adding it as a first argument: qs_replace(haystack, needle, value) or qs_replace(haystack, needle, options)

Code (examples at bottom). Fiddle: http://jsfiddle.net/w8D2G/1/:

function qs_replace(haystack, needle, options) {
    if(!haystack || !needle) return ""; // Without a haystack or needle.. Bye
    else if(typeof needle == "object") {
        options = needle;
        needle = haystack;
        haystack = location.search;
    } else if(typeof options == "undefined") {
        options = needle;
        needle = haystack;
        haystack = location.search;
    }

    if(typeof options == "string" && options != "") {
        options = {remove: options};
        var toggle = true;
    } else if(typeof options != "object" || options === null) {
        return haystack;
    } else {
        var toggle = !!options.toggle;
        if (toggle) {
            options.remove = options.toggle;
            options.toggle = void 0;
        }
    }

    var find = options.find,
        add = options.add,
        remove = options.remove || options.del, //declare remove
        sep = options.sep || options.separator || ",", //Commas, by default

        flags = (options.ignorecase ? "i" :"");

    needle = encodeURIComponent(needle); //URL-encoding
    var pattern = regexp_special_chars(needle);
    pattern = "([?&])(" + pattern + ")(=|&|$)([^&]*)(&|$)";
    pattern = new RegExp(pattern, flags);
    var subquery_match = haystack.match(pattern);

    var before = /\?/.test(haystack) ? "&" : "?"; //Use ? if not existent, otherwise &
    var re_sep = regexp_special_chars(sep);

    if (!add || find) { //add is not defined, or find is used
        var original_remove = remove;
        if (subquery_match) {
            remove = encodeURIComponent(remove);
            remove = regexp_special_chars(remove);
            remove = "(^|" + re_sep + ")(" + remove + ")(" + re_sep + "|$)";
            remove = new RegExp(remove, flags);
            var fail = subquery_match[4].match(remove);
        } else {
            var fail = false;
        }
        if (!add && !fail && toggle) add = original_remove;
    }
    if(find) return !!subquery_match || fail;
    if (add) { //add is a string, defined previously
        add = encodeURIComponent(add);
        if(subquery_match) {
            var re_add = regexp_special_chars(add);
            re_add = "(^|" + re_sep + ")(" + re_add + ")(?=" + re_sep + "|$)";
            re_add = new RegExp(re_add, flags);
            if (subquery_match && re_add.test(subquery_match[4])) {
                return haystack;
            }
            if (subquery_match[3] != "=") {
                subquery_match = "$1$2=" + add + "$4$5";
            } else {
                subquery_match = "$1$2=$4" + sep + add + "$5";
            }
            return haystack.replace(pattern, subquery_match);
        } else {
            return haystack + before + needle + "=" + add;
        }
    } else if(subquery_match){ // Remove part. We can only remove if a needle exist
        if(subquery_match[3] != "="){
            return haystack;
        } else {
            return haystack.replace(pattern, function(match, prefix, key, separator, value, trailing_sep){
                // The whole match, example: &foo=bar,doo
                // will be replaced by the return value of this function
                var newValue = value.replace(remove, function(m, pre, bye, post){
                    return pre == sep && post == sep ? sep : pre == "?" ? "?" : "";
                });
                if(newValue) { //If the value has any content
                    return prefix + key + separator + newValue + trailing_sep;
                } else {
                    return prefix == "?" ? "?" : trailing_sep; //No value, also remove needle
                }
            }); //End of haystack.replace
        } //End of else if
    } else {
        return haystack;
    }

    // Convert string to RegExp-safe string
    function regexp_special_chars(s){
        return s.replace(/([[^$.|?*+(){}\\])/g, '\\$1');
    }
}

Examples (Fiddle: http://jsfiddle.net/w8D2G/1/):

qs_replace('color', 'red'); //Toggle color=red
qs_replace('size', {add: 'medium'}); //Add `medium` if not exist to size
var starting_url = 'http://example.com?color=red&size=small,medium,large&shape=round'
starting_url = qs_replace(starting_url, 'color', 'red'); //Toggle red, thus remove
starting_url = qs_replace(starting_url, 'color', 'red'); //Toggle red, so add it
alert(starting_url);

This is the solution for your task: http://jsfiddle.net/mikhailov/QpjZ3/12/

var url = 'http://example.com?size=small,medium,large&shape=round';
var params = $.deparam.querystring(url);
var paramsResult = {};

var click1 = { size: 'small' };
var click2 = { size: 'xlarge' };
var click3 = { shape: 'round' };
var click4 = { shape: 'square' };

var clickNow = click4;

for (i in params) {
    var clickKey = _.keys(clickNow)[0];
    var clickVal = _.values(clickNow)[0];

    if (i == clickKey) {
       var ar = params[i].split(',');

       if (_.include(ar, clickVal)) {
           var newAr = _.difference(ar, [clickVal]);
       } else {
           var newAr = ar;
           newAr.push(clickVal);
       }
       paramsResult[i] = newAr.join(',');
    } else {
       paramsResult[i] = params[i];
    }

}

alert($.param(paramsResult)) // results see below

Init params string

{ size="small, medium,large", shape="round"} // size=small,medium,large&shape=round

Results

{ size="small"}   => { size="medium,large", shape="round"} //size=medium%2Clarge&shape=round

{ size="xlarge"}  => { size="small,medium,large,xlarge", shape="round"} // size=small%2Cmedium%2Clarge%2Cxlarge&shape=round

{ shape="round"}  => { size="small,medium,large", shape=""} //size=small%2Cmedium%2Clarge&shape=

{ shape="square"} => { size="small,medium,large", shape="round,square"} //size=small%2Cmedium%2Clarge&shape=round%2Csquare

productOptions is the only thing you need to modify here to list all the available options and their default state. You only need to use the public API function toggleOption() to toggle an option.

(function(){
    //Just keep an object with all the options with flags if they are enabled or disabled:

    var productOptions = {

        color: {
            "red": true,
            "blue": true,
            "green": false
        },

        size: {
            "small": true,
            "medium": true,
            "large": true
        },

        shape: {
            "round": true
        }
    };


    //After this constructing query becomes pretty simple even without framework functions:

    function constructQuery(){
    var key, opts, qs = [], enc = encodeURIComponent, opt,
        optAr, i;

        for( key in productOptions ) {
        opts = productOptions[key];
        optAr = [];
            for( i in opts ) {
                if( opts[i] ) {
                optAr.push( i );
                }
            }

            if( !optAr.length ) {
            continue;
            }

        qs.push( enc( key ) + "=" + enc( optAr.join( "," ) ) );
        }

    return "?"+qs.join( "&" );
    };

    //To toggle a value and construct the new query, pass what you want to toggle to this function:

    function toggleOption( optionType, option ) {

        if( optionType in productOptions && option in productOptions[optionType] ) {
        productOptions[optionType][option] = !productOptions[optionType][option];
        }

    return constructQuery();
    }

window.toggleOption = toggleOption;
})()

Example use:

// "%2C" = url encoded version of ","

toggleOption(); //Default query returned:
"?color=red%2Cblue&size=small%2Cmedium%2Clarge&shape=round"

toggleOption( "color", "red" ); //Red color removed:
"?color=blue&size=small%2Cmedium%2Clarge&shape=round"

toggleOption( "color", "blue" ); //Blue color removed, no color options so color doesn't show up at all:
"?size=small%2Cmedium%2Clarge&shape=round"

toggleOption( "color", "blue" ); //Blue color enabled again:
"?color=blue&size=small%2Cmedium%2Clarge&shape=round"

toggleOption( "shape", "round" ); //The only shape option removed
"?color=blue&size=small%2Cmedium%2Clarge"

I have tried this and this may give the desire result

<script>
var url='http://example.com?color=red&size=small,medium,large&shape=round';
var mySplitResult = url.split("?");
var domain=mySplitResult[0];
var qstring=mySplitResult[1];
var proparr=new Array();
var valarr=new Array();
var mySplitArr = qstring.split("&");
for (i=0;i<mySplitArr.length;i++){ 
    var temp = mySplitArr[i].split("=");
    proparr[i]=temp[0];
    valarr[i]=temp[1].split(",");   
 }
function toggle(property,value)
{
    var index;
    var yes=0;
    for (i=0;i<proparr.length;i++){ 
    if(proparr[i]==property)
    index=i;
    }
    if(index==undefined){
    proparr[i]=property;
    index=i;
    valarr[index]=new Array();  
    }   
    for (i=0;i<valarr[index].length;i++){ 
        if(valarr[index][i]==value){
        valarr[index].splice(i,1);
        yes=1;
        }   
    }
    if(!yes)
    {
    valarr[index][i]=value;
    }
    var furl=domain +'?';
    var test=new Array();
    for(i=0;i<proparr.length;i++)
    {
    if(valarr[i].length)
    {
    test[i]=valarr[i].join(",");
    furl +=proparr[i]+"="+test[i]+"&";  
    }   
    }
    furl=furl.substr(0,furl.length-1)
    alert(furl);
}
</script>


<div>
<input id="color" type="button" value="Toggle Red" onclick="toggle('color','red')"/>
<input id="shape" type="button" value="Toggle shape" onclick="toggle('shape','round')"/>
<input id="size" type="button" value="Toggle Small" onclick="toggle('size','small')"/>
<input id="size" type="button" value="Toggle large" onclick="toggle('size','large')"/>
<input id="size" type="button" value="Toggle medium" onclick="toggle('size','medium')"/>
<input id="size" type="button" value="Toggle new" onclick="toggle('new','yes')"/>
</div>

You can toggle a query param easily like this:

const searchParams = new URLSearchParams(window.location.search);

if (searchParams.has('color')) {
    searchParams.delete('color');
} else {
    searchParams.set('color', 'red');
}

window.location.search = searchParams.toString();

Working example:

const currentURLDebug = document.getElementById('current-url-debug');
const toggleColorButton = document.getElementById('toggle-color-button');

toggleColorButton.addEventListener('click', () => {
    const currentURL = new URL(currentURLDebug.textContent);
    const searchParams = new URLSearchParams(currentURL.search);

    if (searchParams.has('color')) {
        searchParams.delete('color');
    } else {
        searchParams.set('color', 'red');
    }
    currentURL.search = searchParams.toString();
    currentURLDebug.textContent = currentURL;
}, false);
<span id="current-url-debug">https://example.com</span>
<br>
<button id="toggle-color-button">Toggle color</button>

发布评论

评论列表(0)

  1. 暂无评论