Skip to content

Instantly share code, notes, and snippets.

@justsml
Last active January 23, 2016 05:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save justsml/c3c0951862dbb73cbfb3 to your computer and use it in GitHub Desktop.
Save justsml/c3c0951862dbb73cbfb3 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 ( succinct +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 ( succinct +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:
- var n = 1 // offset to simplify adding the 'First' link //
ul.pagination
li: a.start(href='#{ transformUrl({page: 1}) }') &laquo; First
while n < pageCount
- n++
li: a(href='#{ transformUrl({page: n}) }'): b #{ n }
if pageCount > 1 && currentPage < pageCount
li: a.end(href='#{ transformUrl({page: pageCount}) }') Last &raquo;
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();
}
@JoshAaronLevy
Copy link

Example 1:

Typically, navigation tabs in a page are not reflected in the URL. This can be problematic for a UX because page refreshes (either manual or automatic, like after someone saves a setting change) do not reload on the tab the user was previously on. The following example is how you can ensure a visitor doesn't lose their place on your site if they are navigating through tabs:

Starting URL: https://github.com/justsml?tab=repositories
Transform W/: {tab: 'activity'}
Updated URL: https://github.com/justsml?tab=activity

Example 2:

If you have a site where visitors can modify or filter the content on the page (like sorting or filtering products on an online store or search results), transforming the URL is a critical component to a friendly UX. For instance, if someone wants to save a list of products they have sorted by price in ascending order, without the URL transformation they will be able to save the list, but it won't have their price sort preference saved when they pull up the list. The following example is how to ensure a visitor can revisit a page on your site in the exact state they modified it:

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:

This example is for developers who wish to provide their site visitors with a UX that is both personalized AND persistent throughout the site. It's for instances where a visitor can select a theme they like for when they visit your site, and most importantly, have that theme selection retained throughout the entirety of their visit. The first two transformations include the examples from above:

Starting URL: https://github.com/justsml?tab=repositories&foo=bar&theme=clouds
Transform W/: {tab: 'activity', sort: 'newest', theme: 'robot'}
Updated URL: https://github.com/justsml?tab=activity&sort=newest&foo=bar&theme=robot

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment