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

Commit

Permalink
feat(input): add ng:minlength and ng:maxlength validation
Browse files Browse the repository at this point in the history
notes(igor): I also e2e tests and refactorred the e2e test example to be
more clear about what is a variable and what is an html/framework api.
  • Loading branch information
kstep authored and IgorMinar committed Oct 19, 2011
1 parent e82e64d commit 78f394f
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 18 deletions.
108 changes: 90 additions & 18 deletions src/widget/input.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ var INTEGER_REGEXP = /^\s*(\-|\+)?\d+\s*$/;
* @param {string} ng:model Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the widgets is published.
* @param {string=} required Sets `REQUIRED` validation error key if the value is not entered.
* @param {number=} ng:minlength Sets `MINLENGTH` validation error key if the value is shorter than
* minlength.
* @param {number=} ng:maxlength Sets `MAXLENGTH` validation error key if the value is longer than
* maxlength.
* @param {string=} ng:pattern Sets `PATTERN` validation error key if the value does not match the
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
* patterns defined as scope expressions.
Expand Down Expand Up @@ -79,6 +83,10 @@ var INTEGER_REGEXP = /^\s*(\-|\+)?\d+\s*$/;
* @param {string} ng:model Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the widgets is published.
* @param {string=} required Sets `REQUIRED` validation error key if the value is not entered.
* @param {number=} ng:minlength Sets `MINLENGTH` validation error key if the value is shorter than
* minlength.
* @param {number=} ng:maxlength Sets `MAXLENGTH` validation error key if the value is longer than
* maxlength.
* @param {string=} ng:pattern Sets `PATTERN` validation error key if the value does not match the
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
* patterns defined as scope expressions.
Expand Down Expand Up @@ -146,6 +154,10 @@ angularInputType('email', function() {
* @param {string} ng:model Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the widgets is published.
* @param {string=} required Sets `REQUIRED` validation error key if the value is not entered.
* @param {number=} ng:minlength Sets `MINLENGTH` validation error key if the value is shorter than
* minlength.
* @param {number=} ng:maxlength Sets `MAXLENGTH` validation error key if the value is longer than
* maxlength.
* @param {string=} ng:pattern Sets `PATTERN` validation error key if the value does not match the
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
* patterns defined as scope expressions.
Expand Down Expand Up @@ -288,6 +300,10 @@ angularInputType('list', function() {
* @param {string=} min Sets the `MIN` validation error key if the value entered is less then `min`.
* @param {string=} max Sets the `MAX` validation error key if the value entered is greater then `min`.
* @param {string=} required Sets `REQUIRED` validation error key if the value is not entered.
* @param {number=} ng:minlength Sets `MINLENGTH` validation error key if the value is shorter than
* minlength.
* @param {number=} ng:maxlength Sets `MAXLENGTH` validation error key if the value is longer than
* maxlength.
* @param {string=} ng:pattern Sets `PATTERN` validation error key if the value does not match the
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
* patterns defined as scope expressions.
Expand Down Expand Up @@ -353,6 +369,10 @@ angularInputType('number', numericRegexpInputType(NUMBER_REGEXP, 'NUMBER'));
* @param {string=} min Sets the `MIN` validation error key if the value entered is less then `min`.
* @param {string=} max Sets the `MAX` validation error key if the value entered is greater then `min`.
* @param {string=} required Sets `REQUIRED` validation error key if the value is not entered.
* @param {number=} ng:minlength Sets `MINLENGTH` validation error key if the value is shorter than
* minlength.
* @param {number=} ng:maxlength Sets `MAXLENGTH` validation error key if the value is longer than
* maxlength.
* @param {string=} ng:pattern Sets `PATTERN` validation error key if the value does not match the
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
* patterns defined as scope expressions.
Expand Down Expand Up @@ -601,6 +621,10 @@ var HTML5_INPUTS_TYPES = makeMap(
* @param {string} ng:model Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the widgets is published.
* @param {string=} required Sets `REQUIRED` validation error key if the value is not entered.
* @param {number=} ng:minlength Sets `MINLENGTH` validation error key if the value is shorter than
* minlength.
* @param {number=} ng:maxlength Sets `MAXLENGTH` validation error key if the value is longer than
* maxlength.
* @param {string=} ng:pattern Sets `PATTERN` validation error key if the value does not match the
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
* patterns defined as scope expressions.
Expand All @@ -612,32 +636,69 @@ var HTML5_INPUTS_TYPES = makeMap(
<doc:source>
<script>
function Ctrl() {
this.text = 'guest';
this.user = {name: 'guest', last: 'visitor'};
}
</script>
<div ng:controller="Ctrl">
<form name="myForm">
text: <input type="text" name="input" ng:model="text" required>
<span class="error" ng:show="myForm.input.$error.REQUIRED">
Required!</span>
User name: <input type="text" name="userName" ng:model="user.name" required>
<span class="error" ng:show="myForm.userName.$error.REQUIRED">
Required!</span><br>
Last name: <input type="text" name="lastName" ng:model="user.last"
ng:minlength="3" ng:maxlength="10">
<span class="error" ng:show="myForm.lastName.$error.MINLENGTH">
Too short!</span>
<span class="error" ng:show="myForm.lastName.$error.MAXLENGTH">
Too long!</span><br>
</form>
<tt>text = {{text}}</tt><br/>
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
<tt>myForm.$error.REQUIRED = {{!!myForm.$error.REQUIRED}}</tt><br/>
<hr>
<tt>user = {{user}}</tt><br/>
<tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
<tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
<tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
<tt>myForm.userName.$error = {{myForm.lastName.$error}}</tt><br>
<tt>myForm.$valid = {{myForm.$valid}}</tt><br>
<tt>myForm.$error.REQUIRED = {{!!myForm.$error.REQUIRED}}</tt><br>
<tt>myForm.$error.MINLENGTH = {{!!myForm.$error.MINLENGTH}}</tt><br>
<tt>myForm.$error.MAXLENGTH = {{!!myForm.$error.MAXLENGTH}}</tt><br>
</div>
</doc:source>
<doc:scenario>
it('should initialize to model', function() {
expect(binding('text')).toEqual('guest');
expect(binding('myForm.input.$valid')).toEqual('true');
expect(binding('user')).toEqual('{\n \"last\":\"visitor",\n \"name\":\"guest\"}');
expect(binding('myForm.userName.$valid')).toEqual('true');
expect(binding('myForm.$valid')).toEqual('true');
});
it('should be invalid if empty', function() {
input('text').enter('');
expect(binding('text')).toEqual('');
expect(binding('myForm.input.$valid')).toEqual('false');
it('should be invalid if empty when required', function() {
input('user.name').enter('');
expect(binding('user')).toEqual('{\n \"last\":\"visitor",\n \"name\":\"\"}');
expect(binding('myForm.userName.$valid')).toEqual('false');
expect(binding('myForm.$valid')).toEqual('false');
});
it('should be valid if empty when min length is set', function() {
input('user.last').enter('');
expect(binding('user')).toEqual('{\n \"last\":\"",\n \"name\":\"guest\"}');
expect(binding('myForm.lastName.$valid')).toEqual('true');
expect(binding('myForm.$valid')).toEqual('true');
});
it('should be invalid if less than required min length', function() {
input('user.last').enter('xx');
expect(binding('user')).toEqual('{\n \"last\":\"xx",\n \"name\":\"guest\"}');
expect(binding('myForm.lastName.$valid')).toEqual('false');
expect(binding('myForm.lastName.$error')).toMatch(/MINLENGTH/);
expect(binding('myForm.$valid')).toEqual('false');
});
it('should be valid if longer than max length', function() {
input('user.last').enter('some ridiculously long name');
expect(binding('user'))
.toEqual('{\n \"last\":\"some ridiculously long name",\n \"name\":\"guest\"}');
expect(binding('myForm.lastName.$valid')).toEqual('false');
expect(binding('myForm.lastName.$error')).toMatch(/MAXLENGTH/);
expect(binding('myForm.$valid')).toEqual('false');
});
</doc:scenario>
</doc:example>
Expand All @@ -656,6 +717,8 @@ angularWidget('input', function(inputElement){
modelScope = this,
patternMatch, widget,
pattern = trim(inputElement.attr('ng:pattern')),
minlength = parseInt(inputElement.attr('ng:minlength'), 10),
maxlength = parseInt(inputElement.attr('ng:maxlength'), 10),
loadFromScope = type.match(/^\s*\@\s*(.*)/);


Expand Down Expand Up @@ -711,15 +774,24 @@ angularWidget('input', function(inputElement){
widget.$pristine = !(widget.$dirty = false);

widget.$on('$validate', function(event) {
var $viewValue = trim(widget.$viewValue);
var inValid = widget.$required && !$viewValue;
var missMatch = $viewValue && !patternMatch($viewValue);
var $viewValue = trim(widget.$viewValue),
inValid = widget.$required && !$viewValue,
tooLong = maxlength && $viewValue && $viewValue.length > maxlength,
tooShort = minlength && $viewValue && $viewValue.length < minlength,
missMatch = $viewValue && !patternMatch($viewValue);

if (widget.$error.REQUIRED != inValid){
widget.$emit(inValid ? '$invalid' : '$valid', 'REQUIRED');
}
if (widget.$error.PATTERN != missMatch){
widget.$emit(missMatch ? '$invalid' : '$valid', 'PATTERN');
}
if (widget.$error.MINLENGTH != tooShort){
widget.$emit(tooShort ? '$invalid' : '$valid', 'MINLENGTH');
}
if (widget.$error.MAXLENGTH != tooLong){
widget.$emit(tooLong ? '$invalid' : '$valid', 'MAXLENGTH');
}
});

forEach(['valid', 'invalid', 'pristine', 'dirty'], function(name) {
Expand Down
12 changes: 12 additions & 0 deletions test/widget/inputSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,18 @@ describe('widget: input', function() {
});


itShouldVerify('text with ng:minlength limit',
['', 'aaa', 'aaaaa', 'aaaaaaaaa'],
['a', 'aa'],
{'ng:minlength': 3});


itShouldVerify('text with ng:maxlength limit',
['', 'a', 'aa', 'aaa'],
['aaaa', 'aaaaa', 'aaaaaaaaa'],
{'ng:maxlength': 3});


it('should throw an error when scope pattern can\'t be found', function() {
var el = jqLite('<input ng:model="foo" ng:pattern="fooRegexp">'),
scope = angular.compile(el)();
Expand Down

0 comments on commit 78f394f

Please sign in to comment.