/ ajax

Smart Query Strings part 2: AJAX

This is a version of the PHP snippet I wrote last post, but for JavaScript (specifically jQuery for AJAX calls).

Basically, using the same type of call as before, you can use this to keep track of previously set variables set for AJAX calls. That way, you can easily keep all of the other parameters (good for multiple filter options passed via AJAX) and change only what you need. The code's a smidgen more complicated for this one.

function buildQueryString(changesString, currentString) {  
    if(!currentString || currentString == undefined)  {  
        // get the current URL  
        var href = window.location.href;

        // get the part after the ?  
        var queryStringHash = href.slice(href.indexOf('?') + 1);

        // if it exists, cut off the # and after  
        if(queryStringHash.indexOf('#') < 0)  
            var queryString = queryStringHash;  
        else  
            var queryString = queryStringHash.slice(0, queryStringHash.indexOf('#'));  
    } else {  
        // strip ?  
        if(currentString.indexOf('?') >= 0)  
        queryString = currentString  
        .slice(currentString.indexOf('?') + 1);  
    }

    // strip ?  
    if(changesString.indexOf('?') >= 0)  
        changesString = changesString.slice(changesString.indexOf('?') + 1);

    // turn strings into  
    var query = queryStringToArray(queryString);  
    var change = queryStringToArray(changesString);

    if(query.indexOf('undefined') < 0) query = [];

    // this gets fun... look to see if each change matches  
    // then if it is, change the query value.  
    // if it's not found, then add it to the query  
    for(var i=0; i < change.length; i++) {  
        var found = false;
        for(var j=0; j < query.length; j++) {  
        // compare each change value with query value, etc  
        if(query[j].name === change[i].name) {  
            query[j].value = change[i].value;  
            found = true;  
        }  
    }     

    // did find it, so we have to append it  
    if(!found)  
        query.push($.parseJSON('{"name":' + '"' +  change[i].name + '","value":"' + change[i].value + '"}'))  
    }

    // save it to currentQueryString for use next time (i.e. for AJAX calls)  
    currentQueryString = $.param(query);

    // turn it back into a string  
    return $.param(query);  
}  

It's reliant on this little helper function that turns a query string of parameters (i.e. sort=name&page=3&dir=DESC) into an array;

function queryStringToArray(queryString) {  
    var queryVariablePairs = queryString.split("&");

    var queryArray = [];

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

        queryJSON = '{"name":' + '"' + queryParts[0] + '","value":"' +  
        queryParts[1] + '"}';

        queryArray.push($.parseJSON(queryJSON));  
    }

    return queryArray;  
}  

Here's an example of usage:

HTML

<a href="?a=1&b=2&c=3">Click Me!</a>

JavaScript:

// IMPORTANT -> This variable keeps track of the variables in the last call.  
var current = undefined;  
$(document).ready(function() {  
    $('a').click(function(event) {  
        var changes = $(this).attr('href');

        var data = buildQueryString(changes, current);  
        $.post("action.php", data, function(response) { 
            $('body').append(response); 
        });  
    });  
});  

Quick explanation of why it's useful: If the last query string used in an AJAX call had the parameters b = 7 and d = 5, then the query string you'd have sent would be b=7&d=5. If you click on the "Click Me" link, it would build a string changing b to 2 and adding a and c and leaving d alone, creating a=1&b=2&c=3&d=5. It's easy to see how this could be useful when a user can apply multiple simultaneous filters to a dataset.