diff --git a/src/urlMatcherFactory.js b/src/urlMatcherFactory.js index 8a0c27a99..1b0422d07 100644 --- a/src/urlMatcherFactory.js +++ b/src/urlMatcherFactory.js @@ -261,7 +261,7 @@ UrlMatcher.prototype.exec = function (path, searchParams) { var param = this.params[paramName]; var paramVal = m[i+1]; // if the param value matches a pre-replace pair, replace the value before decoding. - for (j = 0; j < param.replace; j++) { + for (j = 0; j < param.replace.length; j++) { if (param.replace[j].from === paramVal) paramVal = param.replace[j].to; } if (paramVal && param.array === true) paramVal = decodePathArray(paramVal); @@ -368,6 +368,7 @@ UrlMatcher.prototype.format = function (values) { } else { if (encoded == null || (isDefaultValue && squash !== false)) continue; if (!isArray(encoded)) encoded = [ encoded ]; + if (encoded.length === 0) continue; encoded = map(encoded, encodeURIComponent).join('&' + name + '='); result += (search ? '&' : '?') + (name + '=' + encoded); search = true; @@ -532,6 +533,7 @@ Type.prototype.$asArray = function(mode, isSearch) { // Wraps type (.is/.encode/.decode) functions to operate on each value of an array function arrayHandler(callback, allTruthyMode) { return function handleArray(val) { + if (isArray(val) && val.length === 0) return val; val = arrayWrap(val); var result = map(val, callback); if (allTruthyMode === true) diff --git a/test/urlMatcherFactorySpec.js b/test/urlMatcherFactorySpec.js index a57a26582..3ef72a8f6 100755 --- a/test/urlMatcherFactorySpec.js +++ b/test/urlMatcherFactorySpec.js @@ -272,6 +272,8 @@ describe("UrlMatcher", function () { expect(m.exec($location.path(), $location.search())).toEqual( { param1: undefined } ); $location.url("/foo?param1=bar"); expect(m.exec($location.path(), $location.search())).toEqual( { param1: 'bar' } ); // auto unwrap + $location.url("/foo?param1="); + expect(m.exec($location.path(), $location.search())).toEqual( { param1: undefined } ); $location.url("/foo?param1=bar¶m1=baz"); if (angular.isArray($location.search())) // conditional for angular 1.0.8 expect(m.exec($location.path(), $location.search())).toEqual( { param1: ['bar', 'baz'] } ); @@ -334,6 +336,29 @@ describe("UrlMatcher", function () { expect(m.format({ "param1[]": ['bar', 'baz'] })).toBe("/foo?param1[]=bar¶m1[]=baz"); })); + // Test for issue #2222 + it("should return default value, if query param is missing.", inject(function($location) { + var m = new UrlMatcher('/state?param1¶m2¶m3¶m5', { + params: { + param1 : 'value1', + param2 : {array: true, value: ['value2']}, + param3 : {array: true, value: []}, + param5 : {array: true, value: function() {return [];}} + } + }); + + var parsed = m.exec("/state"); + var expected = { + "param1": 'value1', + "param2": ['value2'], + "param3": [], + "param5": [] + }; + + expect(parsed).toEqualData(expected) + expect(m.params.$$values(parsed)).toEqualData(expected); + })); + it("should not be wrapped by ui-router into an array if array: false", inject(function($location) { var m = new UrlMatcher('/foo?param1', { params: { param1: { array: false } } });