So recently, I needed a quick easy way to both access query string
parameters as an object and to output that object as a query string. I
found a meta-plugin that Joern had written a while back for parsing
into an object and I decided to expand on that. The two key features I
added were a 'set' method for adding new things to the object and
adding a toString method so that when outputting in the context of a
string the object would, by default, convert to the proper querystring
representation. The advantage of this is you can do something like
this:

var newPath = location.pathname + $.query.set("id", 5).set("view",
"details")

And it will add id and view to the query object and output the
resultant query string. It's not as nice as if you have direct object
access but getters and setters aren't really cross-browser friendly.
And besides, this syntax duplicates the chaining of methods seen in
jQuery so frequently.

Before anyone asks, this is a side-effect-less method. set() returns a
new instance of the object so $.query remains the same. There is an
optional boolean argument you can use to modify the original object
but it's not good practice. Anyways, enough prattle, here's the code:

jQuery.query = new function() {
  var queryObject = function(a, destructive) {
    var self = this;
    self.keys = {};
    self.destructive = destructive === true ? true : false;
    if (a.queryObject) {
      jQuery.each(a.keys, function(key, val) {
        self.destructiveSet(key, val);
      });
    } else {
      var q = "" + a;
      q = q.replace(/^\?/,''); // remove any leading ?
      q = q.replace(/\&$/,''); // remove any trailing &
      jQuery.each(q.split('&'), function(){
        var key = this.split('=')[0];
        var val = this.split('=')[1];
        if(/^[0-9.]+$/.test(val))
          val = parseFloat(val);
        else if (/^[0-9]+$/.test(val))
          val = parseInt(val);
        if (!isNaN(val))
          self.destructiveSet(key, val || true);
      });
    }
    return this;
  };

  queryObject.prototype = {
    queryObject: true,
    get: function(key) {
      return this.keys[key];
    },
    destructiveSet: function(key, val) {
      if (val == undefined || val === null)
        this.destructiveRemove(key);
      else
        this[key] = this.keys[key] = val;
      return this;
    },
    set: function(key, val, destructive) {
      var self = ((destructive === true ? true : this.destructive) ===
true) ? this : new queryObject(this);
      return self.destructiveSet(key, val);
    },
    destructiveRemove: function(key) {
      if (typeof this.keys[key] != 'undefined') {
        delete this.keys[key];
        delete this[key];
      }
      return this;
    },
    remove: function(key, destructive) {
      var self = ((destructive === true ? true : this.destructive) ===
true) ? this : new queryObject(this);
      return self.destructiveRemove(key);
    },
    toString: function() {
      var i = 0, queryString = [];
      jQuery.each(this.keys, function(key, value) {
        var o = [];
        if (value !== false) {
          if (i++ == 0)
            o.push("?");
          o.push(key);
          if (value !== true) {
            o.push("=");
            o.push(encodeURIComponent(value));
          }
        }
        queryString.push(o.join(""));
      });
      return queryString.join("&");
    }
  };

  return new queryObject(location.search);

};

-blair

Reply via email to