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

Commit 78f394f

Browse files
kstepIgorMinar
authored andcommitted
feat(input): add ng:minlength and ng:maxlength validation
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.
1 parent e82e64d commit 78f394f

File tree

2 files changed

+102
-18
lines changed

2 files changed

+102
-18
lines changed

src/widget/input.js

+90-18
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ var INTEGER_REGEXP = /^\s*(\-|\+)?\d+\s*$/;
1616
* @param {string} ng:model Assignable angular expression to data-bind to.
1717
* @param {string=} name Property name of the form under which the widgets is published.
1818
* @param {string=} required Sets `REQUIRED` validation error key if the value is not entered.
19+
* @param {number=} ng:minlength Sets `MINLENGTH` validation error key if the value is shorter than
20+
* minlength.
21+
* @param {number=} ng:maxlength Sets `MAXLENGTH` validation error key if the value is longer than
22+
* maxlength.
1923
* @param {string=} ng:pattern Sets `PATTERN` validation error key if the value does not match the
2024
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
2125
* patterns defined as scope expressions.
@@ -79,6 +83,10 @@ var INTEGER_REGEXP = /^\s*(\-|\+)?\d+\s*$/;
7983
* @param {string} ng:model Assignable angular expression to data-bind to.
8084
* @param {string=} name Property name of the form under which the widgets is published.
8185
* @param {string=} required Sets `REQUIRED` validation error key if the value is not entered.
86+
* @param {number=} ng:minlength Sets `MINLENGTH` validation error key if the value is shorter than
87+
* minlength.
88+
* @param {number=} ng:maxlength Sets `MAXLENGTH` validation error key if the value is longer than
89+
* maxlength.
8290
* @param {string=} ng:pattern Sets `PATTERN` validation error key if the value does not match the
8391
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
8492
* patterns defined as scope expressions.
@@ -146,6 +154,10 @@ angularInputType('email', function() {
146154
* @param {string} ng:model Assignable angular expression to data-bind to.
147155
* @param {string=} name Property name of the form under which the widgets is published.
148156
* @param {string=} required Sets `REQUIRED` validation error key if the value is not entered.
157+
* @param {number=} ng:minlength Sets `MINLENGTH` validation error key if the value is shorter than
158+
* minlength.
159+
* @param {number=} ng:maxlength Sets `MAXLENGTH` validation error key if the value is longer than
160+
* maxlength.
149161
* @param {string=} ng:pattern Sets `PATTERN` validation error key if the value does not match the
150162
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
151163
* patterns defined as scope expressions.
@@ -288,6 +300,10 @@ angularInputType('list', function() {
288300
* @param {string=} min Sets the `MIN` validation error key if the value entered is less then `min`.
289301
* @param {string=} max Sets the `MAX` validation error key if the value entered is greater then `min`.
290302
* @param {string=} required Sets `REQUIRED` validation error key if the value is not entered.
303+
* @param {number=} ng:minlength Sets `MINLENGTH` validation error key if the value is shorter than
304+
* minlength.
305+
* @param {number=} ng:maxlength Sets `MAXLENGTH` validation error key if the value is longer than
306+
* maxlength.
291307
* @param {string=} ng:pattern Sets `PATTERN` validation error key if the value does not match the
292308
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
293309
* patterns defined as scope expressions.
@@ -353,6 +369,10 @@ angularInputType('number', numericRegexpInputType(NUMBER_REGEXP, 'NUMBER'));
353369
* @param {string=} min Sets the `MIN` validation error key if the value entered is less then `min`.
354370
* @param {string=} max Sets the `MAX` validation error key if the value entered is greater then `min`.
355371
* @param {string=} required Sets `REQUIRED` validation error key if the value is not entered.
372+
* @param {number=} ng:minlength Sets `MINLENGTH` validation error key if the value is shorter than
373+
* minlength.
374+
* @param {number=} ng:maxlength Sets `MAXLENGTH` validation error key if the value is longer than
375+
* maxlength.
356376
* @param {string=} ng:pattern Sets `PATTERN` validation error key if the value does not match the
357377
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
358378
* patterns defined as scope expressions.
@@ -601,6 +621,10 @@ var HTML5_INPUTS_TYPES = makeMap(
601621
* @param {string} ng:model Assignable angular expression to data-bind to.
602622
* @param {string=} name Property name of the form under which the widgets is published.
603623
* @param {string=} required Sets `REQUIRED` validation error key if the value is not entered.
624+
* @param {number=} ng:minlength Sets `MINLENGTH` validation error key if the value is shorter than
625+
* minlength.
626+
* @param {number=} ng:maxlength Sets `MAXLENGTH` validation error key if the value is longer than
627+
* maxlength.
604628
* @param {string=} ng:pattern Sets `PATTERN` validation error key if the value does not match the
605629
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
606630
* patterns defined as scope expressions.
@@ -612,32 +636,69 @@ var HTML5_INPUTS_TYPES = makeMap(
612636
<doc:source>
613637
<script>
614638
function Ctrl() {
615-
this.text = 'guest';
639+
this.user = {name: 'guest', last: 'visitor'};
616640
}
617641
</script>
618642
<div ng:controller="Ctrl">
619643
<form name="myForm">
620-
text: <input type="text" name="input" ng:model="text" required>
621-
<span class="error" ng:show="myForm.input.$error.REQUIRED">
622-
Required!</span>
644+
User name: <input type="text" name="userName" ng:model="user.name" required>
645+
<span class="error" ng:show="myForm.userName.$error.REQUIRED">
646+
Required!</span><br>
647+
Last name: <input type="text" name="lastName" ng:model="user.last"
648+
ng:minlength="3" ng:maxlength="10">
649+
<span class="error" ng:show="myForm.lastName.$error.MINLENGTH">
650+
Too short!</span>
651+
<span class="error" ng:show="myForm.lastName.$error.MAXLENGTH">
652+
Too long!</span><br>
623653
</form>
624-
<tt>text = {{text}}</tt><br/>
625-
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
626-
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
627-
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
628-
<tt>myForm.$error.REQUIRED = {{!!myForm.$error.REQUIRED}}</tt><br/>
654+
<hr>
655+
<tt>user = {{user}}</tt><br/>
656+
<tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
657+
<tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
658+
<tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
659+
<tt>myForm.userName.$error = {{myForm.lastName.$error}}</tt><br>
660+
<tt>myForm.$valid = {{myForm.$valid}}</tt><br>
661+
<tt>myForm.$error.REQUIRED = {{!!myForm.$error.REQUIRED}}</tt><br>
662+
<tt>myForm.$error.MINLENGTH = {{!!myForm.$error.MINLENGTH}}</tt><br>
663+
<tt>myForm.$error.MAXLENGTH = {{!!myForm.$error.MAXLENGTH}}</tt><br>
629664
</div>
630665
</doc:source>
631666
<doc:scenario>
632667
it('should initialize to model', function() {
633-
expect(binding('text')).toEqual('guest');
634-
expect(binding('myForm.input.$valid')).toEqual('true');
668+
expect(binding('user')).toEqual('{\n \"last\":\"visitor",\n \"name\":\"guest\"}');
669+
expect(binding('myForm.userName.$valid')).toEqual('true');
670+
expect(binding('myForm.$valid')).toEqual('true');
635671
});
636672
637-
it('should be invalid if empty', function() {
638-
input('text').enter('');
639-
expect(binding('text')).toEqual('');
640-
expect(binding('myForm.input.$valid')).toEqual('false');
673+
it('should be invalid if empty when required', function() {
674+
input('user.name').enter('');
675+
expect(binding('user')).toEqual('{\n \"last\":\"visitor",\n \"name\":\"\"}');
676+
expect(binding('myForm.userName.$valid')).toEqual('false');
677+
expect(binding('myForm.$valid')).toEqual('false');
678+
});
679+
680+
it('should be valid if empty when min length is set', function() {
681+
input('user.last').enter('');
682+
expect(binding('user')).toEqual('{\n \"last\":\"",\n \"name\":\"guest\"}');
683+
expect(binding('myForm.lastName.$valid')).toEqual('true');
684+
expect(binding('myForm.$valid')).toEqual('true');
685+
});
686+
687+
it('should be invalid if less than required min length', function() {
688+
input('user.last').enter('xx');
689+
expect(binding('user')).toEqual('{\n \"last\":\"xx",\n \"name\":\"guest\"}');
690+
expect(binding('myForm.lastName.$valid')).toEqual('false');
691+
expect(binding('myForm.lastName.$error')).toMatch(/MINLENGTH/);
692+
expect(binding('myForm.$valid')).toEqual('false');
693+
});
694+
695+
it('should be valid if longer than max length', function() {
696+
input('user.last').enter('some ridiculously long name');
697+
expect(binding('user'))
698+
.toEqual('{\n \"last\":\"some ridiculously long name",\n \"name\":\"guest\"}');
699+
expect(binding('myForm.lastName.$valid')).toEqual('false');
700+
expect(binding('myForm.lastName.$error')).toMatch(/MAXLENGTH/);
701+
expect(binding('myForm.$valid')).toEqual('false');
641702
});
642703
</doc:scenario>
643704
</doc:example>
@@ -656,6 +717,8 @@ angularWidget('input', function(inputElement){
656717
modelScope = this,
657718
patternMatch, widget,
658719
pattern = trim(inputElement.attr('ng:pattern')),
720+
minlength = parseInt(inputElement.attr('ng:minlength'), 10),
721+
maxlength = parseInt(inputElement.attr('ng:maxlength'), 10),
659722
loadFromScope = type.match(/^\s*\@\s*(.*)/);
660723

661724

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

713776
widget.$on('$validate', function(event) {
714-
var $viewValue = trim(widget.$viewValue);
715-
var inValid = widget.$required && !$viewValue;
716-
var missMatch = $viewValue && !patternMatch($viewValue);
777+
var $viewValue = trim(widget.$viewValue),
778+
inValid = widget.$required && !$viewValue,
779+
tooLong = maxlength && $viewValue && $viewValue.length > maxlength,
780+
tooShort = minlength && $viewValue && $viewValue.length < minlength,
781+
missMatch = $viewValue && !patternMatch($viewValue);
782+
717783
if (widget.$error.REQUIRED != inValid){
718784
widget.$emit(inValid ? '$invalid' : '$valid', 'REQUIRED');
719785
}
720786
if (widget.$error.PATTERN != missMatch){
721787
widget.$emit(missMatch ? '$invalid' : '$valid', 'PATTERN');
722788
}
789+
if (widget.$error.MINLENGTH != tooShort){
790+
widget.$emit(tooShort ? '$invalid' : '$valid', 'MINLENGTH');
791+
}
792+
if (widget.$error.MAXLENGTH != tooLong){
793+
widget.$emit(tooLong ? '$invalid' : '$valid', 'MAXLENGTH');
794+
}
723795
});
724796

725797
forEach(['valid', 'invalid', 'pristine', 'dirty'], function(name) {

test/widget/inputSpec.js

+12
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,18 @@ describe('widget: input', function() {
550550
});
551551

552552

553+
itShouldVerify('text with ng:minlength limit',
554+
['', 'aaa', 'aaaaa', 'aaaaaaaaa'],
555+
['a', 'aa'],
556+
{'ng:minlength': 3});
557+
558+
559+
itShouldVerify('text with ng:maxlength limit',
560+
['', 'a', 'aa', 'aaa'],
561+
['aaaa', 'aaaaa', 'aaaaaaaaa'],
562+
{'ng:maxlength': 3});
563+
564+
553565
it('should throw an error when scope pattern can\'t be found', function() {
554566
var el = jqLite('<input ng:model="foo" ng:pattern="fooRegexp">'),
555567
scope = angular.compile(el)();

0 commit comments

Comments
 (0)