From e99194ddd6549d61daca6d817eb24e652b28a792 Mon Sep 17 00:00:00 2001 From: Alex Spurling Date: Wed, 1 May 2013 12:40:41 +0100 Subject: [PATCH 1/5] fix(ngList) Fix model to view rendering when using a custom separator This change adds a new ng-list-joined-by attribute to the ngList directive. This allows you to specify a custom string to join elements of the model array together which is useful when you are also using a custom separator. Example: This will split an input string such as "Cat | Mouse | Dog" into the array ["Cat", "Mouse", "Dog"] and vice versa. --- src/ng/directive/input.js | 18 +++++++++-- test/ng/directive/inputSpec.js | 56 ++++++++++++++++++++++++++++++++-- 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index 8ab6f696ca81..7cf9b2ec8f23 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -1263,8 +1263,20 @@ var ngListDirective = function() { return { require: 'ngModel', link: function(scope, element, attr, ctrl) { - var match = /\/(.*)\//.exec(attr.ngList), - separator = match && new RegExp(match[1]) || attr.ngList || ','; + // Get the attribute values directly from the element rather than the + // attr map otherwise the attribute values will be trimmed of whitespace + var separatorAttribute = element[0].getAttribute("ng-list") + var joinedByAttribute = element[0].getAttribute("ng-list-joined-by") + var separator, joinedby; + var match = /\/(.*)\//.exec(separatorAttribute); + if (match) { + // This is a regex pattern - always use ', ' to join elements when ngListJoinedBy is undefined + separator = new RegExp(match[1]) + joinedby = joinedByAttribute || ', '; + }else{ + separator = separatorAttribute || ',' + joinedby = joinedByAttribute || separatorAttribute || ', '; + } var parse = function(viewValue) { var list = []; @@ -1281,7 +1293,7 @@ var ngListDirective = function() { ctrl.$parsers.push(parse); ctrl.$formatters.push(function(value) { if (isArray(value)) { - return value.join(', '); + return value.join(joinedby); } return undefined; diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index f8898074f13e..b6efc4c17ff6 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -1009,23 +1009,75 @@ describe('input', function() { it('should allow custom separator', function() { compileInput(''); - changeInputValueTo('a,a'); - expect(scope.list).toEqual(['a,a']); + // model -> view + scope.$apply(function() { + scope.list = ['x', 'y', 'z']; + }); + expect(inputElm.val()).toBe('x:y:z'); //Should use the separator as the join string + // view -> model changeInputValueTo('a:b'); expect(scope.list).toEqual(['a', 'b']); }); + it('should allow custom separator with whitespace', function() { + compileInput(''); + + changeInputValueTo('House or Door or Chair'); + expect(scope.list).toEqual(['House', 'Door', 'Chair']); + }); + + + it('should allow custom join string', function() { + compileInput(''); + + // model -> view + scope.$apply(function() { + scope.list = ['x', 'y', 'z']; + }); + expect(inputElm.val()).toBe('x and y and z'); + }); + + + it('should allow custom separator and custom join string', function() { + compileInput(''); + + // model -> view + scope.$apply(function() { + scope.list = ['x', 'y', 'z']; + }); + expect(inputElm.val()).toBe('x and y and z'); + }); + + it('should allow regexp as a separator', function() { compileInput(''); + // model -> view + scope.$apply(function() { + scope.list = ['x', 'y', 'z']; + }); + expect(inputElm.val()).toBe('x, y, z'); //Should use ', ' as the default join string + + // view -> model changeInputValueTo('a,b'); expect(scope.list).toEqual(['a', 'b']); changeInputValueTo('a,b: c'); expect(scope.list).toEqual(['a', 'b', 'c']); }); + + + it('should allow regexp as a separator and custom join string', function() { + compileInput(''); + + // model -> view + scope.$apply(function() { + scope.list = ['x', 'y', 'z']; + }); + expect(inputElm.val()).toBe('x; y; z'); + }); }); describe('required', function() { From 290c4b65830b288c5247756c85ba5cc541aa0e44 Mon Sep 17 00:00:00 2001 From: Alex Spurling Date: Thu, 2 May 2013 09:40:45 +0100 Subject: [PATCH 2/5] doc(ngList) Document ngListJoinedBy parameter of ngList --- src/ng/directive/input.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index 7cf9b2ec8f23..01d548a0ed04 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -1225,6 +1225,8 @@ var requiredDirective = function() { * @element input * @param {string=} ngList optional delimiter that should be used to split the value. If * specified in form `/something/` then the value will be converted into a regular expression. + * @param {string=} ngListJoinedBy optional string to use when joining elements of the array. + * This is especially useful when the delimeter is a regular expression. The default value is ', '. * * @example From 99ad93b85adfb1fd990db3bddd464ec24f45548f Mon Sep 17 00:00:00 2001 From: Alex Spurling Date: Thu, 2 May 2013 13:48:48 +0100 Subject: [PATCH 3/5] refactor(ngList) change ng-list-joined-by to ng-list-join --- src/ng/directive/input.js | 10 +++++----- test/ng/directive/inputSpec.js | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index 01d548a0ed04..182d7957cd6d 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -1225,7 +1225,7 @@ var requiredDirective = function() { * @element input * @param {string=} ngList optional delimiter that should be used to split the value. If * specified in form `/something/` then the value will be converted into a regular expression. - * @param {string=} ngListJoinedBy optional string to use when joining elements of the array. + * @param {string=} ngListJoin optional string to use when joining elements of the array. * This is especially useful when the delimeter is a regular expression. The default value is ', '. * * @example @@ -1268,16 +1268,16 @@ var ngListDirective = function() { // Get the attribute values directly from the element rather than the // attr map otherwise the attribute values will be trimmed of whitespace var separatorAttribute = element[0].getAttribute("ng-list") - var joinedByAttribute = element[0].getAttribute("ng-list-joined-by") + var joinAttribute = element[0].getAttribute("ng-list-join") var separator, joinedby; var match = /\/(.*)\//.exec(separatorAttribute); if (match) { - // This is a regex pattern - always use ', ' to join elements when ngListJoinedBy is undefined + // This is a regex pattern - always use ', ' to join elements when ngListJoin is undefined separator = new RegExp(match[1]) - joinedby = joinedByAttribute || ', '; + joinedby = joinAttribute || ', '; }else{ separator = separatorAttribute || ',' - joinedby = joinedByAttribute || separatorAttribute || ', '; + joinedby = joinAttribute || separatorAttribute || ', '; } var parse = function(viewValue) { diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index b6efc4c17ff6..6a2846f7ef34 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -1030,7 +1030,7 @@ describe('input', function() { it('should allow custom join string', function() { - compileInput(''); + compileInput(''); // model -> view scope.$apply(function() { @@ -1041,7 +1041,7 @@ describe('input', function() { it('should allow custom separator and custom join string', function() { - compileInput(''); + compileInput(''); // model -> view scope.$apply(function() { @@ -1070,7 +1070,7 @@ describe('input', function() { it('should allow regexp as a separator and custom join string', function() { - compileInput(''); + compileInput(''); // model -> view scope.$apply(function() { From d04d3c7670cc0886fcde49db0844599b4ab6aed6 Mon Sep 17 00:00:00 2001 From: Alex Spurling Date: Thu, 2 May 2013 13:53:37 +0100 Subject: [PATCH 4/5] fix(ngList) get ng-list attribute names via attr.$attr This fixes a problem caused when ng-list attributes have non standard but valid names such as ng:list or data-ng-list --- src/ng/directive/input.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index 182d7957cd6d..4f26ed696081 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -1267,8 +1267,8 @@ var ngListDirective = function() { link: function(scope, element, attr, ctrl) { // Get the attribute values directly from the element rather than the // attr map otherwise the attribute values will be trimmed of whitespace - var separatorAttribute = element[0].getAttribute("ng-list") - var joinAttribute = element[0].getAttribute("ng-list-join") + var separatorAttribute = element[0].getAttribute(attr.$attr['ngList']) + var joinAttribute = element[0].getAttribute(attr.$attr['ngListJoin']) var separator, joinedby; var match = /\/(.*)\//.exec(separatorAttribute); if (match) { From 72b75ae6b11f8f15b7b590480f136680901159e3 Mon Sep 17 00:00:00 2001 From: Alex Spurling Date: Thu, 2 May 2013 14:04:00 +0100 Subject: [PATCH 5/5] test(ngList) test with alternative attribute names --- test/ng/directive/inputSpec.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index 6a2846f7ef34..6ec1a25ab412 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -1048,6 +1048,25 @@ describe('input', function() { scope.list = ['x', 'y', 'z']; }); expect(inputElm.val()).toBe('x and y and z'); + + // view -> model + changeInputValueTo('a:b'); + expect(scope.list).toEqual(['a', 'b']); + }); + + + it('should allow custom separator and custom join string in alternative attribute form', function() { + compileInput(''); + + // model -> view + scope.$apply(function() { + scope.list = ['x', 'y', 'z']; + }); + expect(inputElm.val()).toBe('x and y and z'); + + // view -> model + changeInputValueTo('a:b'); + expect(scope.list).toEqual(['a', 'b']); });