Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

feat($location): add queryString method #2701

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Angular.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ function nextUid() {

/**
* Set or clear the hashkey for an object.
* @param obj object
* @param obj object
* @param h the hashkey (!truthy to delete the hashkey)
*/
function setHashKey(obj, h) {
Expand Down
59 changes: 46 additions & 13 deletions src/ng/location.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ function matchUrl(url, obj) {
obj.$$port = int(match[5]) || DEFAULT_PORTS[match[1]] || null;
}

function matchAppUrl(url, obj) {
function matchAppUrl(url, obj, queryString) {
var match = PATH_MATCH.exec(url);

obj.$$path = decodeURIComponent(match[1]);
obj.$$search = parseKeyValue(match[3]);
obj.$$search = queryString.parse(match[3]);
obj.$$hash = decodeURIComponent(match[5] || '');

// make sure path starts with '/';
Expand Down Expand Up @@ -74,6 +74,13 @@ function serverBase(url) {
}



var defaultQueryString = {
stringify: toKeyValue,
parse: parseKeyValue
};


/**
* LocationHtml5Url represents an url
* This object is exposed as $location service when HTML5 mode is enabled and supported
Expand All @@ -82,8 +89,9 @@ function serverBase(url) {
* @param {string} appBase application base URL
* @param {string} basePrefix url path prefix
*/
function LocationHtml5Url(appBase, basePrefix) {
function LocationHtml5Url(appBase, basePrefix, queryString) {
basePrefix = basePrefix || '';
queryString = queryString || defaultQueryString;
var appBaseNoFile = stripFile(appBase);
/**
* Parse given html5 (regular) url string into properties
Expand All @@ -97,7 +105,7 @@ function LocationHtml5Url(appBase, basePrefix) {
if (!isString(pathUrl)) {
throw Error('Invalid url "' + url + '", missing path prefix "' + appBaseNoFile + '".');
}
matchAppUrl(pathUrl, parsed);
matchAppUrl(pathUrl, parsed, queryString);
extend(this, parsed);
if (!this.$$path) {
this.$$path = '/';
Expand All @@ -111,7 +119,7 @@ function LocationHtml5Url(appBase, basePrefix) {
* @private
*/
this.$$compose = function() {
var search = toKeyValue(this.$$search),
var search = queryString.stringify(this.$$search),
hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';

this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
Expand All @@ -134,6 +142,8 @@ function LocationHtml5Url(appBase, basePrefix) {
return appBaseNoFile;
}
}

this.queryString = queryString;
}


Expand All @@ -145,9 +155,11 @@ function LocationHtml5Url(appBase, basePrefix) {
* @param {string} appBase application base URL
* @param {string} hashPrefix hashbang prefix
*/
function LocationHashbangUrl(appBase, hashPrefix) {
function LocationHashbangUrl(appBase, hashPrefix, queryString) {
queryString = queryString || defaultQueryString;
var appBaseNoFile = stripFile(appBase);


/**
* Parse given hashbang url into properties
* @param {string} url Hashbang url
Expand All @@ -163,7 +175,7 @@ function LocationHashbangUrl(appBase, hashPrefix) {
if (!isString(withoutHashUrl)) {
throw new Error('Invalid url "' + url + '", missing hash prefix "' + hashPrefix + '".');
}
matchAppUrl(withoutHashUrl, this);
matchAppUrl(withoutHashUrl, this, queryString);
this.$$compose();
};

Expand All @@ -172,9 +184,9 @@ function LocationHashbangUrl(appBase, hashPrefix) {
* @private
*/
this.$$compose = function() {
var search = toKeyValue(this.$$search),
var search = queryString.stringify(this.$$search),
hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';

this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
};
Expand All @@ -184,6 +196,8 @@ function LocationHashbangUrl(appBase, hashPrefix) {
return url;
}
}

this.queryString = queryString;
}


Expand All @@ -196,7 +210,7 @@ function LocationHashbangUrl(appBase, hashPrefix) {
* @param {string} appBase application base URL
* @param {string} hashPrefix hashbang prefix
*/
function LocationHashbangInHtml5Url(appBase, hashPrefix) {
function LocationHashbangInHtml5Url(appBase, hashPrefix, queryString) {
LocationHashbangUrl.apply(this, arguments);

var appBaseNoFile = stripFile(appBase);
Expand Down Expand Up @@ -360,7 +374,7 @@ LocationHashbangInHtml5Url.prototype =
this.$$search[search] = paramValue;
}
} else {
this.$$search = isString(search) ? parseKeyValue(search) : search;
this.$$search = isString(search) ? this.queryString.parse(search) : search;
}

this.$$compose();
Expand Down Expand Up @@ -456,7 +470,8 @@ function locationGetterSetter(property, preprocess) {
*/
function $LocationProvider(){
var hashPrefix = '',
html5Mode = false;
html5Mode = false,
queryString = defaultQueryString;

/**
* @ngdoc property
Expand Down Expand Up @@ -492,6 +507,24 @@ function $LocationProvider(){
}
};

/**
* @ngdoc property
* @name ng.$locationProvider#queryString
* @methodOf ng.$locationProvider
* @description
* Custom query string encoding and decoding.
*
* @param {object} query string parser with stringify and parse functions
*/
this.queryString = function(qs) {
if (isDefined(qs)) {
queryString = qs;
} else {
return queryString;
}

};

this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement',
function( $rootScope, $browser, $sniffer, $rootElement) {
var $location,
Expand All @@ -507,7 +540,7 @@ function $LocationProvider(){
appBase = stripHash(initialUrl);
LocationMode = LocationHashbangUrl;
}
$location = new LocationMode(appBase, '#' + hashPrefix);
$location = new LocationMode(appBase, '#' + hashPrefix, queryString);
$location.$$parse($location.$$rewrite(initialUrl));

$rootElement.bind('click', function(event) {
Expand Down
22 changes: 21 additions & 1 deletion test/ng/locationSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -385,10 +385,11 @@ describe('$location', function() {
});


function initService(html5Mode, hashPrefix, supportHistory) {
function initService(html5Mode, hashPrefix, supportHistory, queryString) {
return module(function($provide, $locationProvider){
$locationProvider.html5Mode(html5Mode);
$locationProvider.hashPrefix(hashPrefix);
$locationProvider.queryString(queryString);
$provide.value('$sniffer', {history: supportHistory});
});
}
Expand Down Expand Up @@ -651,6 +652,25 @@ describe('$location', function() {
});


describe('setting a custom query string parser', function() {
var qs = {stringify: toJson, parse: fromJson};
beforeEach(initService(true, '', true, qs));
beforeEach(inject(initBrowser('http://domain.com/?{"foo": "bar"}', '/')));

it('should change how query string is parsed', inject(function($location) {
expect($location.search()).toEqual({foo: "bar"});
}));

it('should use parser when setting params', inject(function($location, $browser, $rootScope) {
$location.search('foo', ["bar"]);
$rootScope.$apply();
expect($browser.url()).toEqual('http://domain.com/?{"foo":["bar"]}')
}));

afterEach
});


describe('SERVER_MATCH', function() {

it('should parse basic url', function() {
Expand Down