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

Commit 2c225f4

Browse files
committed
add docs
1 parent 86d373f commit 2c225f4

File tree

4 files changed

+89
-22
lines changed

4 files changed

+89
-22
lines changed

docs/content/error/ngModel/numfmt.ngdoc

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
@fullName Model is not of type `number`
44
@description
55

6-
The number input directive `<input type="number">` requires the model to be a `number`.
6+
The `input[number]` and `input[range]` directives require the model to be a `number`.
77

88
If the model is something else, this error will be thrown.
99

karma-shared.conf.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ module.exports = function(config, specificOptions) {
1717
testName: specificOptions.testName || 'AngularJS',
1818
startConnect: true,
1919
options: {
20-
// We need selenium version +2.46 for Firefox 39 and the last selenium version for OS X is 2.45.
20+
// We need selenium version +2.46 for 'Firefox' 39 and the last selenium version for OS X is 2.45.
2121
// TODO: Uncomment when there is a selenium 2.46 available for OS X.
2222
// 'selenium-version': '2.46.0'
2323
}

src/ng/directive/input.js

+79-18
Original file line numberDiff line numberDiff line change
@@ -1036,22 +1036,49 @@ var inputType = {
10361036
* @name input[range]
10371037
*
10381038
* @description
1039-
* Native range input with validation and transformation. Sets the `number` validation
1040-
* to always have a valid number. Note that IE9 does not support the `range` type, but falls back
1039+
* Native range input with validation and transformation.
1040+
*
1041+
* The model for the range input must always be a `Number`.
1042+
*
1043+
* IE9 does not support the `range` type, but falls back
10411044
* to a text input. Model binding, validation and number parsing are nevertheless supported.
10421045
*
1043-
* @param {string} ngModel Assignable angular expression to data-bind to.
1046+
* Browsers that support range (latest Chrome, Safari, Firefox, Edge) treat `input[range]`
1047+
* in a way that never allows the input to hold an invalid value. That means:
1048+
* - any non-numerical value is set to `(max + min) / 2`.
1049+
* - any numerical value that is less than the current min val, or greater than the current max val
1050+
* is set to the min / max val respectively.
1051+
*
1052+
* This has the following consequences for Angular:
1053+
*
1054+
* Since the element value should always reflect the current model value, a range input
1055+
* will set the bound ngModel expression to the value that the browser has set for the
1056+
* input element. For example, in the following input `<input type="range" ng-model="model.value">`,
1057+
* if I set `model.value = null`, the browser will set the input to `'50'`. Angular will then set
1058+
* the model to `50`, to prevent input and model value being out of sync.
1059+
*
1060+
* This does not only affect changes to the model value, but also to the values of the `min` and
1061+
* `max` attributes. When these change in a way that will cause the browser to modify the input value,
1062+
* Angular will also update the model value.
1063+
*
1064+
* Automatic value adjustment also means that a range input element can never have the `required`,
1065+
* `min`, or `max` errors, except when using `ngMax` and `ngMin`, which are not affected by automatic
1066+
* value adjustment, because they do not set the `min` and `max` attributes.
1067+
*
1068+
* @param {string} ngModel Assignable angular expression to data-bind to.
10441069
* @param {string=} name Property name of the form under which the control is published.
10451070
* @param {string=} min Sets the `min` validation to ensure that the value entered is greater
10461071
* than `min`. Can be interpolated.
10471072
* @param {string=} max Sets the `max` validation to ensure that the value entered is less than `max`.
10481073
* Can be interpolated.
10491074
* @param {string=} ngMin Takes an expression. Sets the `min` validation to ensure that the value
10501075
* entered is greater than `min`. Does not set the `min` attribute and therefore
1051-
* adds no native HTML5 validation.
1076+
* adds no native HTML5 validation. It also means the browser won't adjust the
1077+
* element value in case `min` is greater than the current value.
10521078
* @param {string=} ngMax Takes an expression. Sets the `max` validation to ensure that the value
10531079
* entered is less than `max`. Does not set the `min` attribute and therefore
1054-
* adds no native HTML5 validation.
1080+
* adds no native HTML5 validation. It also means the browser won't adjust the
1081+
* element value in case `max` is less than the current value.
10551082
* @param {string=} ngChange Angular expression to be executed when the ngModel value changes due
10561083
* to user interaction with the input element.
10571084
*
@@ -1062,18 +1089,52 @@ var inputType = {
10621089
angular.module('rangeExample', [])
10631090
.controller('ExampleController', ['$scope', function($scope) {
10641091
$scope.value = 75;
1092+
$scope.min = 10;
1093+
$scope.max = 90;
10651094
}]);
10661095
</script>
10671096
<form name="myForm" ng-controller="ExampleController">
1068-
Number: <input type="range" name="input" ng-model="value"
1069-
min="10" max="90">
1070-
<tt>value = {{value}}</tt><br/>
1071-
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
1072-
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
1073-
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
1097+
1098+
Model as range: <input type="range" name="range" ng-model="value"
1099+
min="{{min}}" max="{{max}}">
1100+
<hr>
1101+
Model as number: <input type="number" ng-model="value"><br>
1102+
Min: <input type="number" ng-model="min"><br>
1103+
Max: <input type="number" ng-model="min"><br>
1104+
value = <code>{{value}}</code><br/>
1105+
myForm.range.$valid = <code>{{myForm.range.$valid}}</code><br/>
1106+
myForm.range.$error = <code>{{myForm.range.$error}}</code>
1107+
</form>
1108+
</file>
1109+
</example>
1110+
1111+
* ## Range Input with ngMin & ngMax attributes
1112+
1113+
* @example
1114+
<example name="range-input-directive-ng" module="rangeExample">
1115+
<file name="index.html">
1116+
<script>
1117+
angular.module('rangeExample', [])
1118+
.controller('ExampleController', ['$scope', function($scope) {
1119+
$scope.value = 75;
1120+
$scope.min = 10;
1121+
$scope.max = 90;
1122+
}]);
1123+
</script>
1124+
<form name="myForm" ng-controller="ExampleController">
1125+
Model as range: <input type="range" name="range" ng-model="value"
1126+
ng-min="10" ng-max="90">
1127+
<hr>
1128+
Model as number: <input type="number" ng-model="value"><br>
1129+
Min: <input type="number" ng-model="min"><br>
1130+
Max: <input type="number" ng-model="min"><br>
1131+
value = <code>{{value}}</code><br/>
1132+
myForm.range.$valid = <code>{{myForm.range.$valid}}</code><br/>
1133+
myForm.range.$error = <code>{{myForm.range.$error}}</code>
10741134
</form>
10751135
</file>
10761136
</example>
1137+
10771138
*/
10781139
'range': rangeInputType,
10791140

@@ -1528,32 +1589,32 @@ function rangeInputType(scope, element, attr, ctrl, $sniffer, $browser) {
15281589
return;
15291590
}
15301591

1531-
// TODO(matsko): implement validateLater to reduce number of validations
15321592
if (supportsRange && minAttrType === 'min') {
15331593
var elVal = element.val();
1534-
// IE11 doesn't set the el val correctly if the maxVal is less than the element value
1594+
// IE11 doesn't set the el val correctly if the minVal is greater than the element value
15351595
if (minVal > elVal) {
15361596
element.val(minVal);
15371597
}
15381598
ctrl.$setViewValue(element.val());
15391599
} else {
1600+
// TODO(matsko): implement validateLater to reduce number of validations
15401601
ctrl.$validate();
15411602
}
15421603
}
15431604

15441605
var minAttrType = isDefined(attr.min) ? 'min' : attr.ngMin ? 'ngMin' : false;
15451606
if (minAttrType) {
1546-
// Since ngMin doesn't set the min attr, the browser doesn't adjust the input value as setting min would
15471607
ctrl.$validators.min = isDefined(attr.min) && supportsRange ?
15481608
function noopMinValidator(value) {
15491609
// Since all browsers set the input to a valid value, we don't need to check validity
15501610
return true;
15511611
} :
1612+
// ngMin doesn't set the min attr, so the browser doesn't adjust the input value as setting min would
15521613
function minValidator(modelValue, viewValue) {
15531614
return ctrl.$isEmpty(viewValue) || isUndefined(minVal) || viewValue >= minVal;
15541615
};
15551616

1556-
// Assign minVal when the directive is linked. This won't $validate as the model isn't ready yet
1617+
// Assign minVal when the directive is linked. This won't run the validators as the model isn't ready yet
15571618
minChange(attr.min);
15581619
attr.$observe('min', minChange);
15591620
}
@@ -1563,7 +1624,6 @@ function rangeInputType(scope, element, attr, ctrl, $sniffer, $browser) {
15631624
val = parseFloat(val);
15641625
}
15651626
maxVal = isNumber(val) && !isNaN(val) ? val : undefined;
1566-
// TODO(matsko): implement validateLater to reduce number of validations
15671627
// ignore changes before model is initialized
15681628
if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
15691629
return;
@@ -1577,22 +1637,23 @@ function rangeInputType(scope, element, attr, ctrl, $sniffer, $browser) {
15771637
}
15781638
ctrl.$setViewValue(element.val());
15791639
} else {
1640+
// TODO(matsko): implement validateLater to reduce number of validations
15801641
ctrl.$validate();
15811642
}
15821643
}
15831644
var maxAttrType = isDefined(attr.max) ? 'max' : attr.ngMax ? 'ngMax' : false;
15841645
if (maxAttrType) {
1585-
// Since ngMax doesn't set the max attr, the browser doesn't adjust the input value as setting max would
15861646
ctrl.$validators.max = isDefined(attr.max) && supportsRange ?
15871647
function noopMaxValidator() {
15881648
// Since all browsers set the input to a valid value, we don't need to check validity
15891649
return true;
15901650
} :
1651+
// ngMax doesn't set the max attr, so the browser doesn't adjust the input value as setting max would
15911652
function maxValidator(modelValue, viewValue) {
15921653
return ctrl.$isEmpty(viewValue) || isUndefined(maxVal) || viewValue <= maxVal;
15931654
};
15941655

1595-
// Assign maxVal when the directive is linked. This won't $validate as the model isn't ready yet
1656+
// Assign maxVal when the directive is linked. This won't run the validators as the model isn't ready yet
15961657
maxChange(attr.max);
15971658
attr.$observe('max', maxChange);
15981659
}

test/ng/directive/inputSpec.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -2823,12 +2823,18 @@ describe('input', function() {
28232823

28242824
var scope;
28252825

2826+
var rangeTestEl = angular.element('<input type="range">');
2827+
var supportsRange = rangeTestEl[0].type === 'range';
28262828
beforeEach(function() {
28272829
scope = $rootScope;
28282830
});
28292831

2830-
var rangeTestEl = angular.element('<input type="range">');
2831-
var supportsRange = rangeTestEl[0].type === 'range';
2832+
it('should parse the input value to a Number', function() {
2833+
var inputElm = helper.compileInput('<input type="range" ng-model="age" />');
2834+
2835+
helper.changeInputValueTo('75');
2836+
expect(scope.age).toBe(75);
2837+
});
28322838

28332839
if (supportsRange) {
28342840
// This behavior only applies to browsers that implement the range input, which do not

0 commit comments

Comments
 (0)