Browse files

Fix min/max validation. Closes gh-666. Fixes #648

In 1.10.0, min/max validation was supported for input type="text",
where min/max were interpreted as numbers.  This means min/max
for date would not work: min="2012-02-13" was interpreted as min="Not a Number".

In 1.11.0, min/max were no longer converted to numbers.  This means
min/max for dates worked, but min/max for numbers failed:
"50" < "150" < "1000" does not hold.

For an example, see http://jsbin.com/awokex/3

This commit makes the behaviour of min/max dependent on input type:

 * input type=text (or not type attribute) has numeric min/max, as in 1.10.0
 * input type=date has working min/max for type date;
   on mobile browsers you also get a date picker,
   plus the browser may reject invalid dates before
   javascript gets a chance to complain.
 * input type=number or range get numeric min/max,
   plus numeric keypad or slider on mobile browsers,
   plus browser may reject invalid input before javascript
   gets a chance to complain

Allowing use of min/max with type=number/range/date is important
for mobile browsers, where the numeric keypad or date picker
make the input much easier to use than a generic text input field.
In this situation jquery-validate remains necessary to support
older browsers that do not do input validation based on type
and min/max.

For situations where numeric input should be validated by jquery
without giving the browser a chance to validate the input format,
input type=text in combination with min/max can be used, as in 1.10.0.
  • Loading branch information...
1 parent 4a134b6 commit 5b114e10db09fa8cb9f5e7f0f3cff234d70269a5 @ekonijn ekonijn committed with Feb 23, 2013
Showing with 150 additions and 20 deletions.
  1. +10 −1 jquery.validate.js
  2. +36 −12 test/index.html
  3. +1 −1 test/rules.js
  4. +103 −6 test/test.js
View
11 jquery.validate.js
@@ -840,6 +840,7 @@ $.extend($.validator, {
attributeRules: function( element ) {
var rules = {};
var $element = $(element);
+ var type = $element[0].getAttribute("type");
for (var method in $.validator.methods) {
var value;
@@ -858,9 +859,17 @@ $.extend($.validator, {
value = $element.attr(method);
}
+ // convert the value to a number for number inputs, and for text for backwards compability
+ // allows type="date" and others to be compared as strings
+ if ( /min|max/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) {
+ value = Number(value);
+ }
+
if ( value ) {
rules[method] = value;
- } else if ( $element[0].getAttribute("type") === method ) {
+ } else if ( type === method && type !== 'range' ) {
+ // exception: the jquery validate 'range' method
+ // does not test for the html5 'range' type
rules[method] = true;
}
}
View
48 test/index.html
@@ -295,20 +295,44 @@ <h2 id="qunit-userAgent"></h2>
<label id="targetLabel" class="error" for="updateLabelInput">Some server-side error</label>
</form>
+ <form id="rangesMinDateInvalid">
+ <input type="date" id="minDateInvalid" name="minDateInvalid" min="2012-12-21" value="2012-11-21"/>
+ </form>
<form id="ranges">
- <input type="text" id="minDateInvalid" name="minDateInvalid" min="2012-12-21" value="2012-11-21"/>
- <input type="text" id="maxDateInvalid" ngame="maxDateInvalid" max="2012-12-21" value="2013-01-21"/>
- <input type="text" id="rangeDateInvalidGreater" name="rangeDateInvalidGreater" min="2012-11-21" max="2013-01-21" value="2013-02-21"/>
- <input type="text" id="rangeDateInvalidLess" name="rangeDateInvalidLess" min="2012-11-21" max="2013-01-21" value="2012-10-21"/>
-
- <input type="text" id="minDateValid" name="minDateValid" min="2012-11-21" value="2012-12-21"/>
- <input type="text" id="maxDateValid" name="maxDateValid" max="2013-01-21" value="2012-12-21"/>
- <input type="text" id="rangeDateValid" name="rangeDateValid" min="2012-11-21" max="2013-01-21" value="2012-12-21"/>
+ <input type="date" id="maxDateInvalid" ngame="maxDateInvalid" max="2012-12-21" value="2013-01-21"/>
+ <input type="date" id="rangeDateInvalidGreater" name="rangeDateInvalidGreater" min="2012-11-21" max="2013-01-21" value="2013-02-21"/>
+ <input type="date" id="rangeDateInvalidLess" name="rangeDateInvalidLess" min="2012-11-21" max="2013-01-21" value="2012-10-21"/>
+
+ <input type="date" id="maxDateValid" name="maxDateValid" max="2013-01-21" value="2012-12-21"/>
+ <input type="date" id="rangeDateValid" name="rangeDateValid" min="2012-11-21" max="2013-01-21" value="2012-12-21"/>
+
+ <!-- input type text is not supposed to have min/max according to html5,
+ but for backward compatibility with 1.10.0 we treat it as number.
+ you can also use type="number", in which case the browser may also
+ do validation, and mobile browsers may offer a numeric keypad to edit
+ the value.
+ Type absent is treated like type="text".
+ -->
+ <input type="text" id="rangeTextInvalidGreater" name="rangeTextInvalidGreater" min="50" max="200" value="1000"/>
+ <input type="text" id="rangeTextInvalidLess" name="rangeTextInvalidLess" min="200" max="1000" value="50"/>
+ <input id="rangeAbsentInvalidGreater" name="rangeAbsentInvalidGreater" min="50" max="200" value="1000"/>
+ <input id="rangeAbsentInvalidLess" name="rangeAbsentInvalidLess" min="200" max="1000" value="50"/>
+
+ <input type="text" id="rangeTextValid" name="rangeTextValid" min="50" max="1000" value="200"/>
+ <input id="rangeAbsentValid" name="rangeTextValid" min="50" max="1000" value="200"/>
+
+ <!-- ranges are like numbers in html5, except that browser is not required
+ to demand an exact value. User interface could be a slider.
+ -->
+ <input type="range" id="rangeRangeValid" name="rangeRangeValid" min="50" max="1000" value="200"/>
+
+ <input type="number" id="rangeNumberValid" name="rangeNumberValid" min="50" max="1000" value="200"/>
+ <input type="number" id="rangeNumberInvalidGreater" name="rangeNumberInvalidGreater" min="50" max="200" value="1000"/>
+ <input type="number" id="rangeNumberInvalidLess" name="rangeNumberInvalidLess" min="50" max="200" value="6"/>
- <input type="text" id="rangeTextInvalidGreater" name="rangeTextInvalidGreater" min="BBB" max="YYY" value="ZZZ"/>
- <input type="text" id="rangeTextInvalidLess" name="rangeTextInvalidLess" min="BBB" max="YYY" value="AAA"/>
-
- <input type="text" id="rangeTextValid" name="rangeTextValid" min="AAA" max="ZZZ" value="NNN"/>
+ </form>
+ <form id="rangeMinDateValid">
+ <input type="date" id="minDateValid" name="minDateValid" min="2012-11-21" value="2012-12-21"/>
</form>
<form id="bypassValidation">
View
2 test/rules.js
@@ -205,7 +205,7 @@ test("rules(), add and remove", function() {
deepEqual( $("#v2-i5").rules(), { required: true, minlength: 2, maxlength: 5, customMethod1: "123" });
$("#v2-i5").addClass("email").attr({min: 5});
- deepEqual( $("#v2-i5").rules(), { required: true, email: true, minlength: 2, maxlength: 5, min: "5", customMethod1: "123" });
+ deepEqual( $("#v2-i5").rules(), { required: true, email: true, minlength: 2, maxlength: 5, min: 5, customMethod1: "123" });
$("#v2-i5").removeClass("required email").removeAttrs("minlength maxlength customMethod1 min");
deepEqual( $("#v2-i5").rules(), {});
View
109 test/test.js
@@ -1331,14 +1331,14 @@ test("Updates pre-existing label if has error class", function() {
});
test("Min date set by attribute", function() {
- var form = $('#ranges');
+ var form = $('#rangesMinDateInvalid');
var name = $('#minDateInvalid');
var v = form.validate();
form.get(0).reset();
name.valid();
- var label = $('#ranges label');
+ var label = $('#rangesMinDateInvalid label');
equal( label.text(), "Please enter a value greater than or equal to 2012-12-21.", "Correct error label" );
});
@@ -1379,14 +1379,14 @@ test("Min and Max date set by attributes less", function() {
});
test("Min date set by attribute valid", function() {
- var form = $('#ranges');
+ var form = $('#rangeMinDateValid');
var name = $('#minDateValid');
var v = form.validate();
form.get(0).reset();
name.valid();
- var label = $('#ranges label');
+ var label = $('#rangeMinDateValid label');
equal( label.text(), "", "Correct error label" );
});
@@ -1423,7 +1423,7 @@ test("Min and Max strings set by attributes greater", function() {
name.valid();
var label = $('#ranges label');
- equal( label.text(), "Please enter a value less than or equal to YYY.", "Correct error label" );
+ equal( label.text(), "Please enter a value less than or equal to 200.", "Correct error label" );
});
test("Min and Max strings set by attributes less", function() {
@@ -1435,7 +1435,7 @@ test("Min and Max strings set by attributes less", function() {
name.valid();
var label = $('#ranges label');
- equal( label.text(), "Please enter a value greater than or equal to BBB.", "Correct error label" );
+ equal( label.text(), "Please enter a value greater than or equal to 200.", "Correct error label" );
});
test("Min and Max strings set by attributes valid", function() {
@@ -1451,3 +1451,100 @@ test("Min and Max strings set by attributes valid", function() {
});
+
+test("Min and Max type absent set by attributes greater", function() {
+ var form = $('#ranges');
+ var name = $('#rangeAbsentInvalidGreater');
+ var v = form.validate();
+
+ form.get(0).reset();
+ name.valid();
+
+ var label = $('#ranges label');
+ equal( label.text(), "Please enter a value less than or equal to 200.", "Correct error label" );
+});
+
+test("Min and Max type absent set by attributes less", function() {
+ var form = $('#ranges');
+ var name = $('#rangeAbsentInvalidLess');
+ var v = form.validate();
+
+ form.get(0).reset();
+ name.valid();
+
+ var label = $('#ranges label');
+ equal( label.text(), "Please enter a value greater than or equal to 200.", "Correct error label" );
+});
+
+test("Min and Max type absent set by attributes valid", function() {
+ var form = $('#ranges');
+ var name = $('#rangeAbsentValid');
+ var v = form.validate();
+
+ form.get(0).reset();
+ name.valid();
+
+ var label = $('#ranges label');
+ equal( label.text(), "", "Correct error label" );
+});
+
+
+
+test("Min and Max range set by attributes valid", function() {
+ //
+ // cannot test for overflow:
+ // When the element is suffering from an underflow,
+ // the user agent must set the element's value to a valid
+ // floating-point number that represents the minimum.
+ // http://www.w3.org/TR/html5/forms.html#range-state-%28type=range%29
+ //
+ var form = $('#ranges');
+ var name = $('#rangeRangeValid');
+ var v = form.validate();
+
+ form.get(0).reset();
+ name.valid();
+
+ var label = $('#ranges label');
+ equal( label.text(), "", "Correct error label" );
+});
+
+
+test("Min and Max number set by attributes valid", function() {
+ var form = $('#ranges');
+ var name = $('#rangeNumberValid');
+ var v = form.validate();
+
+ form.get(0).reset();
+ name.valid();
+
+ var label = $('#ranges label');
+ equal( label.text(), "", "Correct error label" );
+});
+
+
+test("Min and Max number set by attributes greater", function() {
+ var form = $('#ranges');
+ var name = $('#rangeNumberInvalidGreater');
+ var v = form.validate();
+
+ form.get(0).reset();
+ name.valid();
+
+ var label = $('#ranges label');
+ equal( label.text(), "Please enter a value less than or equal to 200.", "Correct error label" );
+});
+
+
+test("Min and Max number set by attributes less", function() {
+ var form = $('#ranges');
+ var name = $('#rangeNumberInvalidLess');
+ var v = form.validate();
+
+ form.get(0).reset();
+ name.valid();
+
+ var label = $('#ranges label');
+ equal( label.text(), "Please enter a value greater than or equal to 50.", "Correct error label" );
+});
+

0 comments on commit 5b114e1

Please sign in to comment.