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

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: angular/angular.js
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: e82e64d
Choose a base ref
...
head repository: angular/angular.js
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: a46f2a0
Choose a head ref
  • 3 commits
  • 2 files changed
  • 2 contributors

Commits on Oct 19, 2011

  1. 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.
    kstep authored and IgorMinar committed Oct 19, 2011
    Copy the full SHA
    78f394f View commit details
  2. Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    3217a24 View commit details
  3. Copy the full SHA
    a46f2a0 View commit details
Showing with 138 additions and 27 deletions.
  1. +126 −27 src/widget/input.js
  2. +12 −0 test/widget/inputSpec.js
153 changes: 126 additions & 27 deletions src/widget/input.js
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ var EMAIL_REGEXP = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/;
var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
var INTEGER_REGEXP = /^\s*(\-|\+)?\d+\s*$/;


/**
* @ngdoc inputType
* @name angular.inputType.text
@@ -16,6 +17,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.
@@ -79,6 +84,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.
@@ -135,6 +144,7 @@ angularInputType('email', function() {
});
});


/**
* @ngdoc inputType
* @name angular.inputType.url
@@ -146,6 +156,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.
@@ -204,6 +218,7 @@ angularInputType('url', function() {
});
});


/**
* @ngdoc inputType
* @name angular.inputType.list
@@ -275,6 +290,7 @@ angularInputType('list', function() {
};
});


/**
* @ngdoc inputType
* @name angular.inputType.number
@@ -288,6 +304,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.
@@ -340,6 +360,7 @@ angularInputType('list', function() {
*/
angularInputType('number', numericRegexpInputType(NUMBER_REGEXP, 'NUMBER'));


/**
* @ngdoc inputType
* @name angular.inputType.integer
@@ -353,6 +374,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.
@@ -405,6 +430,7 @@ angularInputType('number', numericRegexpInputType(NUMBER_REGEXP, 'NUMBER'));
*/
angularInputType('integer', numericRegexpInputType(INTEGER_REGEXP, 'INTEGER'));


/**
* @ngdoc inputType
* @name angular.inputType.checkbox
@@ -476,9 +502,9 @@ angularInputType('checkbox', function(inputElement) {
widget.$parseView = function() {
widget.$modelValue = widget.$viewValue ? trueValue : falseValue;
};

});


/**
* @ngdoc inputType
* @name angular.inputType.radio
@@ -601,6 +627,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.
@@ -612,32 +642,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>
@@ -656,6 +723,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*(.*)/);


@@ -702,31 +771,37 @@ angularWidget('input', function(inputElement){
controller: TypeController,
controllerArgs: [inputElement]});

widget.$pattern =
watchElementProperty(this, widget, 'required', inputElement);
watchElementProperty(this, widget, 'readonly', inputElement);
watchElementProperty(this, widget, 'disabled', 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);
widget.$on('$validate', function() {
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) {
widget.$watch('$' + name, function(scope, value) {
inputElement[value ? 'addClass' : 'removeClass']('ng-' + name);
}
);
inputElement[value ? 'addClass' : 'removeClass']('ng-' + name);
});
});

inputElement.bind('$destroy', function() {
@@ -756,9 +831,34 @@ angularWidget('input', function(inputElement){
});
}
});

});


/**
* @ngdoc widget
* @name angular.widget.textarea
*
* @description
* HTML textarea element widget with angular data-binding. The data-binding and validation
* properties of this element are exactly the same as those of the
* {@link angular.widget.input input element}.
*
* @param {string} type Widget types as defined by {@link angular.inputType}. If the
* type is in the format of `@ScopeType` then `ScopeType` is loaded from the
* current scope, allowing quick definition of type.
* @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.
* @param {string=} ng:change Angular expression to be executed when input changes due to user
* interaction with the input element.
*/
angularWidget('textarea', angularWidget('input'));


@@ -777,4 +877,3 @@ function watchElementProperty(modelScope, widget, name, element) {
});
}
}

12 changes: 12 additions & 0 deletions test/widget/inputSpec.js
Original file line number Diff line number Diff line change
@@ -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)();