Skip to content

Instantly share code, notes, and snippets.

@osv
Last active September 18, 2015 13:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save osv/95eb50f060fbbb210425 to your computer and use it in GitHub Desktop.
Save osv/95eb50f060fbbb210425 to your computer and use it in GitHub Desktop.
angular pretty url like "/search/city=Dnipropetrovsk;gender=female;time=8:00..12:00"
'use strict';
angular.module('app')
/*
* Next service used to make more readable url
*
* Example:
*
* $stateProvider
* .state('searchfilter', {
* url: '/searchfilter{filter:string}', // not :any, but :string type
*
* ...
*
* // somewhere in your controller:
*
* var params = {
* city: 'Katowice',
* date: new Date()
* },
* encodedParams = filterUrlSerializer.encode(params);
*
* // Make url looks like: /searchfilter;city=Katowice;date=2015-08-28
* $state.go('searchfilter', {filter: encodedParams});
* // and to restore from string:
* var filterParam = filterUrlSerializer.decode($stateParams.filter);
*
*
* Other solution - use own urlMatcher type.
*
* http://angular-ui.github.io/ui-router/site/#/api/ui.router.util.$urlMatcherFactory
*
* However I can't make it work properly. Built-in type "json" that may be good start point for
* serialize/de-serialize not work in this project, it call twice controller.
*
*/
.factory('filterUrlSerializer', [ function () {
var URL_PARAM_SEPARATOR = ';',
PROPERTY_SEPARATOR = '=',
CLOCK_RANGE_SEPARATOR = '..',
ACTIVITY_SEPARATOR = ',',
DATE_CAPTURE_RE = /([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])/; // onetime compile re
var KNOWN_URL_PARAMS = [
{
key: 'city',
paramName: 'city'
},
{
key: 'date',
paramName: 'date',
enc: function (value) {
var asDate = new Date(value),
yyyy = asDate.getFullYear(),
mm = ('0' + (asDate.getMonth() + 1)).slice(-2), // month start from 0, so +1
dd = ('0' + asDate.getDate()).slice(-2),
dateAsStr = [ yyyy, mm, dd ].join('-');
return dateAsStr;
},
dec: function(value) {
var match = DATE_CAPTURE_RE.exec(value);
return match ? new Date(match[1], match[2] - 1, match[3]) : undefined;
}
},
{
key: 'gender',
paramName: 'gender'
},
{
key: 'clockRange',
paramName: 'time',
enc: function(value) {
// MediaWiki use ':' in their URLs to designate namespaces, with apparently no major problems.
// eg http://en.wikipedia.org/wiki/Template:Welcome
var clockStart = value[0] || '8:00',
clockEnd = value[1] || '12:00';
return clockStart + CLOCK_RANGE_SEPARATOR + clockEnd;
},
dec: function(value) {
var ranges = value.split(CLOCK_RANGE_SEPARATOR);
return ranges;
}
},
{
key: 'tag',
paramName: 'tag',
},
{
key: 'activity',
paramName: 'activity',
enc: function(value) {
return value.join(ACTIVITY_SEPARATOR);
},
dec: function(value) {
return value.split(ACTIVITY_SEPARATOR);
},
},
];
return {
encode: function(params) {
var res = [];
KNOWN_URL_PARAMS.forEach(function (p) {
var filterKeyName = p.key,
filterValue = params[filterKeyName],
urlParamName = p.paramName,
encoder = p.enc || function(value) { return value; };
if (! _.isUndefined(filterValue)) {
var encodedParam = encoder(filterValue);
if (encodedParam !== '') {
res.push(urlParamName + PROPERTY_SEPARATOR + encodedParam);
}
}
});
return res.join(URL_PARAM_SEPARATOR);
},
decode: function(stringified) {
var params = stringified.split(URL_PARAM_SEPARATOR),
result = {};
_.each(params, function (param) {
var parts = param.split(PROPERTY_SEPARATOR),
paramName = parts[0],
value = parts[1];
if (! paramName) {
return;
}
var knownParam = _.findWhere(KNOWN_URL_PARAMS, {paramName: paramName});
if (! knownParam) {
console.log('decode url, unknown filter param: "%s", "%s"', paramName, value);
return;
}
var filterKeyName = knownParam.key,
decoder = knownParam.dec,
filterValue = decoder ? decoder(value) : value;
result[filterKeyName] = filterValue;
});
return result;
},
};
}])
// configure route
.config(function ($stateProvider) {
$stateProvider
.state('searchfilter', {
url: '/search/{filter:string}', // <- string!
templateUrl: 'app/searchfilter/searchfilter.html',
controller: 'SearchfilterCtrl',
});
});
// ...
var params = {
city: city,
gender: 'male',
clockRange: ['8:00', '12:00'],
date: date,
},
encodedParams = filterUrlSerializer.encode(params);
$state.go('searchfilter', {filter: encodedParams});
// ..
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment