diff --git a/src/ng/http.js b/src/ng/http.js index 1b295f9908b7..9d272ba9599f 100644 --- a/src/ng/http.js +++ b/src/ng/http.js @@ -11,6 +11,8 @@ var JSON_PROTECTION_PREFIX = /^\)\]\}',?\n/; function paramSerializerFactory(jQueryMode) { + return jQueryMode ? jQueryLikeParamSerializer : paramSerializer; + function serializeValue(v) { if (isObject(v)) { return isDate(v) ? v.toISOString() : toJson(v); @@ -18,23 +20,47 @@ function paramSerializerFactory(jQueryMode) { return v; } - return function paramSerializer(params) { + function paramSerializer(params) { if (!params) return ''; var parts = []; forEachSorted(params, function(value, key) { if (value === null || isUndefined(value)) return; - if (isArray(value) || isObject(value) && jQueryMode) { + if (isArray(value)) { forEach(value, function(v, k) { - var keySuffix = jQueryMode ? '[' + (!isArray(value) ? k : '') + ']' : ''; - parts.push(encodeUriQuery(key + keySuffix) + '=' + encodeUriQuery(serializeValue(v))); + parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(v))); }); } else { parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(value))); } }); - return parts.length > 0 ? parts.join('&') : ''; - }; + return parts.join('&'); + } + + function jQueryLikeParamSerializer(params) { + if (!params) return ''; + var parts = []; + serialize(params, '', true); + return parts.join('&'); + + function serialize(toSerialize, prefix, topLevel) { + if (toSerialize === null || isUndefined(toSerialize)) return; + if (isArray(toSerialize)) { + forEach(toSerialize, function(value) { + serialize(value, prefix + '[]'); + }); + } else if (isObject(toSerialize) && !isDate(toSerialize)) { + forEachSorted(toSerialize, function(value, key) { + serialize(value, prefix + + (topLevel ? '' : '[') + + key + + (topLevel ? '' : ']')); + }); + } else { + parts.push(encodeUriQuery(prefix) + '=' + encodeUriQuery(serializeValue(toSerialize))); + } + } + } } function $HttpParamSerializerProvider() { diff --git a/test/ng/httpSpec.js b/test/ng/httpSpec.js index 79078321c3b6..8f2199119d95 100644 --- a/test/ng/httpSpec.js +++ b/test/ng/httpSpec.js @@ -1992,6 +1992,8 @@ describe('$http param serializers', function() { it('should serialize objects', function() { expect(defSer({foo: 'foov', bar: 'barv'})).toEqual('bar=barv&foo=foov'); expect(jqrSer({foo: 'foov', bar: 'barv'})).toEqual('bar=barv&foo=foov'); + expect(defSer({someDate: new Date('2014-07-15T17:30:00.000Z')})).toEqual('someDate=2014-07-15T17:30:00.000Z'); + expect(jqrSer({someDate: new Date('2014-07-15T17:30:00.000Z')})).toEqual('someDate=2014-07-15T17:30:00.000Z'); }); }); @@ -2010,10 +2012,16 @@ describe('$http param serializers', function() { expect(decodeURIComponent(jqrSer({a: 'b', foo: ['bar', 'baz']}))).toEqual('a=b&foo[]=bar&foo[]=baz'); }); - it('should serialize objects by repeating param name with [kay] suffix', function() { + it('should serialize objects by repeating param name with [key] suffix', function() { expect(jqrSer({a: 'b', foo: {'bar': 'barv', 'baz': 'bazv'}})).toEqual('a=b&foo%5Bbar%5D=barv&foo%5Bbaz%5D=bazv'); //a=b&foo[bar]=barv&foo[baz]=bazv }); + + it('should serialize nested objects by repeating param name with [key] suffix', function() { + expect(jqrSer({a: ['b', {c: 'd'}], e: {f: 'g', 'h': ['i', 'j']}})).toEqual( + 'a%5B%5D=b&a%5B%5D%5Bc%5D=d&e%5Bf%5D=g&e%5Bh%5D%5B%5D=i&e%5Bh%5D%5B%5D=j'); + //a[]=b&a[][c]=d&e[f]=g&e[h][]=i&e[h][]=j + }); }); });