Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dhigginbotham/53b321045ce7054f001b to your computer and use it in GitHub Desktop.
Save dhigginbotham/53b321045ce7054f001b to your computer and use it in GitHub Desktop.
Safer Way to Manipulate a QueryString and Return Modified URL

HOWTO: Easy QueryString Parameter Overrides

A Safer Way to Manipulate a QueryString and Return Modified URL

Demo/Example URL Transform

# Example 1 - Update current query's `tab` value
Starting URL:        https://github.com/justsml?tab=repositories
Transform W/:        {tab: 'activity'}
Updated  URL:        https://github.com/justsml?tab=activity

# Example 2 - Update `tab` + Add `sort` key-value 
Starting URL:        https://github.com/justsml?tab=repositories
Transform W/:        {tab: 'activity', sort: 'newest'}
Updated  URL:        https://github.com/justsml?tab=activity&sort=newest

# Example 3 - Leave existing value `foo` + Update `hello` to an escaped str value
Starting URL:        https://github.com/justsml?tab=repositories&foo=bar&hello=world
Transform W/:        {tab: 'activity', sort: 'newest', hello: 'Mrs. Robinson'}
Updated  URL:        https://github.com/justsml?tab=activity&sort=newest&foo=bar&hello=Mrs%2E%20Robinson

Objectives

  1. Use Hash/Object Map to Define QueryString Changes ( predictable +1 )
  2. Preserve Current QueryString Params - Only change/add specified key-values. ( Code re-use, module portability +1 )
  3. Hide messy & unsafe string hackery, slicing or concatenation. (Functional pattern implemented as NodeJS/Express middleware) +1 +1 +1
  4. Url transform function must be idempotent ( predictable +1 )
  5. Use webpack/browserify on client. Nodejs on the server. ( Always a +10 )
  6. Make template code more human readable. (Adhoc URL hacks/concats can be hard to follow & globally search)
  7. Ideally support adhoc or arbitrary URL mutations (up to any number of QueryString key-value pairs)

Example UI w/ URL+QueryString Options Overrides

For API (single fn), see transformUrl function below.

UI implementation example features 2 common use-cases, implemented as a Jade template. Jade is not required - could be run anywhere JS is spoken (incl. these template engines: EJS, swig, dot.js, Mustache, etc.).

Client-side Usage / Notes

AJAX-ify the pattern by using transformUrl to return client-side URL patterns, perhaps either like:

  1. Use the Url Hash, instead of the querystring, OR
  2. Intercept page redirects, OR
  3. Use a custom attribute on links - e.g. <a href-ajax="/leads/?limit=10">Go</a> - then intercept clicks which target $('a[href-ajax]')
//////////////////////////////////
// Example 'Filter' Toolbar Buttons
ul.nav-bar
li: a(href='#{ transformUrl({limit: 100}) }') Show More
li: a(href='#{ transformUrl({limit: 20}) }') Show Less
// `sort` modifier links (can stay on same page - or return to 1st on sort, w/ {page: 1, sort: "-createdDate"}
li: a(href='#{ transformUrl({sort: "-createdDate"}) }') Show Newest
li: a(href='#{ transformUrl({sort: "createdDate"}) }') Show Oldest
//////////////////////////////////
// Example Pager Render:
ul.pagination
li: a.start(href='#{ transformUrl({page: 1}) }') &laquo; First
each n in pageList
li: a(href='#{ transformUrl({page: n}) }'): b #{ n }
if pageCount > 1 && currentPage < pageCount
li: a.end(href='#{ transformUrl({page: pageCount}) }') Last &raquo;
var transformUrl = require('./transform-url');
function pageList(req, res, next) {
res.locals.currentPage = req.query.page || 1;
res.locals.pageCount = db.count({});
res.locals.pageList = Array.apply(1, Array(res.locals.pagination.pageCount));
};
// this is how you'd sorta expect to get access to pgs
app.get('/',
pageList,
transformUrl,
function(req, res) {
res.render('example-url-transformer');
});
var qs = require('querystring');
module.exports = function _txUrlMiddleware(req, res, next) {
res.locals.transformUrl = function _urlify(opts) {
return req.baseUrl + '?' + qs.stringify(_.extend({}, req.query, opts));
}
next();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment