问题
If I use an input field of type="number" with step="100". I don't want odd numbers to be invalid. I just want increase or decrease to be with a value of 1000.
<input type="number" min="100" max="999999" step="100" />
If the user enters the value "199" and submits, he/she gets an error because the value isn't dividable by 100. But all I want with the step-value is to control the behavior of the spinner, e.g. if the user click up I want the value 199 to become 200 and if he/she clicks down I want it to become 100. Or ideally I would like the value to be increased or decreased with a value of 100.
How do I do this? I tried using the invalid event (with jQuery 1.7.2) like this:
$( "[type='number']" ).bind( 'invalid', function( e ) {
var el = $( this ),
val = el.val( ),
min = el.attr( 'min' ),
max = el.attr( 'max' );
if ( val >= min && val <= max ) {
return false;
}
} );
But this results in the form not being submitted.
PS.: This is in Google Chrome 20.0.1132.57 on Fedora 16.
回答1:
I don't think you can, the step
and the validation are closely tied together. In the future you may be able to override the stepUp() and stepDown() functions to get the behaviour you describe but I've not researched if this is an intended use case for these things. I would recommend posting on the WHATWG mailing list, asking specifically about those functions and describing your use case.
For current practical purposes have you tried setting step=1
and binding to a click
event to capture? I can see there'll probably be an issue with distinguishing between 'up' and 'down' clicks but that might be surmountable. It might be easier all round however to use a text
input, set the pattern
attribute appropriately and implement your own spinner.
回答2:
Well, first of all thank you for this very interesting question. I've learned a lot about HTML5 validation by searching a solution to your problem.
My research led me to find that HTML5 form validation API has an interesting set of properties that are read-only, but very useful to do what you want.
My approach to your problem was to first add the novalidate
attribute to the form element, so that I can control when to trigger the validation, then read the validity
object attached to the input, so I can know exactly what validation errors are there, and if the only error is stepMismatch
(this is what triggers invalidity of numbers such as 199), I can bypass all the validation process. Else, I can show normal HTML validation behaviour with the reportValidity() method.
Here is the code I came up with that I hope does what you want :
var form = document.querySelector("form") // Get the form
var input = document.querySelector("#myInput") // Get the input to validate
form.addEventListener("submit", function(e) {
e.preventDefault() // Catch the submit
// Do the magic
if(onlyStepMatters(input.validity)){
form.submit()
}else {
form.reportValidity()
}
})
function onlyStepMatters(validityState) {
return !(
validityState.badInput || validityState.customError || validityState. patternMismatch || validityState.rangeOverflow || validityState.rangeUnderflow || validityState.tooLong || validityState.tooShort || validityState.typeMismatch || validityState.valueMissing
)
/* This is what the object looks like, notice I just skipped the stepMismatch */
/*
{
badInput,
customError,
patternMismatch,
rangeOverflow,
rangeUnderflow,
stepMismatch,
tooLong,
tooShort,
typeMismatch,
valid,
valueMissing,
}
*/
}
<form novalidate>
<input type="number" id="myInput" min="0" max="1000" step = "100" placeholder="Enter a number" required/>
<button type="submit">Send</button>
</form>
I'm pretty sure this code could be refactored and become more concise based on the same logic, but I don't have enough time to think more about it.
Any constructive comment will be appreciated.
Hope this helps.
回答3:
Only with step but you can use range and add marks to slider then use javascript to check the near value and set it
like
function updateTextInput(val) {
if (val > 36) val = 50;
else if (val > 26) val = 36;
else if (val > 20) val = 26;
else if (val > 15) val = 20;
else if (val > 1) val = 15;
document.getElementById('textInput').value = val;
}
<input type='range' min='0' max='50' step='1' name='slide' list="settings" onchange="updateTextInput(this.value);">
<datalist id="settings">
<option>15</option>
<option>20</option>
<option>26</option>
<option>36</option>
<option>50</option>
</datalist>
<input type="text" id="textInput" />
回答4:
Here is the needed code to achieve what you asked, I tried to avoid recalculations and changing standard behavior so this should be transparent to any other constrain one would set (required, pattern, ranges ...).
I only tested on Firefox and Chrome but I believe it should work on any recent browser.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Disable validity constrains</title>
<!-- avoid highlight due to constrains -->
<style>#qty { box-shadow: unset; }</style>
</head>
<body>
<form>
<input id="qty" name="num" type="number" min="100" max="1000" step="100">
<input type="submit">
</form>
<script>
(function() {
var el = document.getElementById('qty');
el && el.addEventListener('invalid', function(event) {
if ('validity' in el) {
for (var state in el.validity) {
if (state == 'stepMismatch') { continue; }
if (el.validity[state]) { return true; }
}
event.preventDefault();
el.form.submit();
}
}, true);
})();
</script>
</body>
</html>
回答5:
inside "change" event round to nearest valid value.
$( "[type='number']" ).change(function () {
var value = $(this).val());
var newValue = Math.round(value/100)*100
if (newValue < 100) {
newValue = 100;
}
if (newValue > 999999) {
newValue = 999999;
}
if (newValue === value ) {
return;
}
$(this).val(newValue)
})
回答6:
Try using change() function ...
<form>
<input type="number" id="number" min="100" max="999999" step="100" />
</form>
$(document).ready(function(){
$("#number").change(function(a){
if ($(this).val() % 100 === 0) {
/* Do something when the number is even */
console.log("EVEN");
} else {
/* Or when it's odd (isn't dividable by 100), do ... whatever */
console.log("ODD");
}
})
});
And I was testing it using bootstrap, like the example you want, when user click up the value will become 200 (from 199), when the user click down the value will become 100
To change dividable :
if ($(this).val() % 100 === 0) { //Change 100 with what ever you want
回答7:
I've been playing a little with your code, trying to achieve this:
ideally I would like the value to be increased or decreased with a value of 100
… and ended-up with some script to:
- Detect a step increase or decrease by keyboard or mouse,
- Use a
remainder
variable to store the result of the calculation:value % 100
, - Modify the
step
parameter and thevalue
of theinput
, - Add back the
remainder
variable when keyboard or mouse event has ended, and reset thestep
parameter back to1
(needed to be able to submit).
In this working snippet, try to modify the input value with the arrows (on keyboard or with the mouse), starting with a number not divisable by 100:
var remainder = false;
var stepbefore;
$("[type='number']").bind('keydown mousedown', function() {
// If keyboard Up or Down arrow keys or mouse left button on the arrows
if (event.keyCode == 38 || event.keyCode == 40 || event.button === 0) {
// If there is already a change running, exit the function
if (remainder !== false) return;
var myStep = this.getAttribute("stepcustom"); // Get my "stepcustom" attribute
remainder = this.value % myStep;
this.value = Math.floor(this.value / myStep) * myStep;
stepbefore = this.step;
this.step = myStep;
}
});
$("[type='number']").bind('keyup mouseup', function() {
if (remainder !== false) {
this.value = +(this.value) + remainder;
this.step = stepbefore;
remainder = false;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<form>
<input type="number" min="100" max="999999" step="1" stepcustom="100" />
<input type="submit" />
</form>
Hope it helps.
回答8:
This is a simple javascript function that could help you out
where prev_num is global variable
this will work for increment and decrement both
var perv_num=0;
function ax(z)
{
let def;
let mul=10;
let valu;
let valucopy=parseInt(z.value);
let frst;
valucopy=((valucopy+100)%100);
if (parseInt( z.value)<100)
{
document.getElementById("myNumber").value="";
document.getElementById("myNumber").value=100;
}
else if(parseInt( z.value)<perv_num)
{
def=parseInt( z.value.length);
mul=Math.pow(mul,def-1);
frst=(parseInt(z.value[0])*mul);
document.getElementById("myNumber").value="";
document.getElementById("myNumber").value=frst;
}
else if(valucopy ==0)
{
document.getElementById("myNumber").value="";
document.getElementById("myNumber").value=parseInt(z.value)+100;
}
else{
def=parseInt( z.value.length);
mul=Math.pow(mul,def-1);
frst=(parseInt(z.value[0])*mul);
valu=Math.abs( parseInt(z.value)-frst);
valu=100-valu;
var number=(parseInt(z.value)+valu);
document.getElementById("myNumber").value="";
document.getElementById("myNumber").value= number;
}
perv_num=parseInt( z.value);
}
and html is like
<input type="number" id="myNumber" onchange="ax(this)">
fiddle is https://jsfiddle.net/ecpy5gr0/1
回答9:
I make script to change step attribute dynamically:
/*
jQuery Optional Number Step
Version: 1.0.0
Author: Arthur Shlain
Repo: https://github.com/ArthurShlain/JQuery-Optional-Step
Issues: https://github.com/ArthurShlain/JQuery-Optional-Step/issues
*/
(function ($) {
$.fn.optionalNumberStep = function (step) {
var $base = $(this);
var $body = $('body');
$body.on("mouseenter mousemove", '[data-optional-step]', function () {
$(this).attr("step", $(this).attr('data-optional-step'));
});
$body.on("mouseleave blur", '[data-optional-step]', function () {
$(this).removeAttr("step");
});
$body.on("keydown", '[data-optional-step]', function () {
var key = event.which;
switch (key) {
case 38: // Key up.
$(this).attr("step", step);
break;
case 40: // Key down.
$(this).attr("step", step);
break;
default:
$(this).removeAttr("step");
break;
}
});
if (step === 'unset') {
$base.removeAttr('data-optional-step');
}
if ($.isNumeric(step)) {
$base.attr('data-optional-step', step);
}
}
}(jQuery));
jQuery(function() {
$('.optional-step-100').optionalNumberStep(100);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container mt-5">
<h1>JQuery Optional Number Step</h1>
<div class="form-group" style="max-width: 300px">
<label>Example</label>
<input type="number" class="form-control optional-step-100" value="0">
<small id="emailHelp" class="form-text text-muted">Dynamic step for this field is 100
<br>You can specify any numeric value on keyboard.
<br>HTML5 step validation will not be applied.</small>
</div>
<a class="btn btn-dark btn-sm" href="https://github.com/ArthurShlain/JQuery-Optional-Step" target="_blank">View on GitHub</a>
</div>
https://codepen.io/ArtZ91/pen/omePje
来源:https://stackoverflow.com/questions/11738726/html5-input-type-number-change-step-behavior