I created an input of type number. Minimum value 1, maximum value 100. Step 5. However, I can enter values other than step for this input. Eg 7 instead of 5-10-15.
I would like the manually entered values to be automatically increased to the step value. The user enters 7 - after leaving the input it is 10. I am trying onfocusout but I have no idea how to do it.
<input type="number" min="1" max="100" step="5" onfocusout="this.value = Math.round(step);">
Example. The user enters 13 - gets 15. He enters 27 - gets 30.
CodePudding user response:
you can :
get the result of value divided by 5
round the result to near integer
and multiply it by 5 to get the nearest 5 value of the input entered by user
this.value = Math.round(this.value / 5) * 5;
<input type="number" min="1" max="100" step="5" onfocusout="var result = Math.round(this.value / 5) * 5; this.value = (result) ? result : this.min ;">
CodePudding user response:
First, instead of listening for focusout
events you should listen for change
events, which are triggered whenever the user does anything that implies they are done entering a value. This will make the behavior more consistent across browsers and devices.
Second, you can round a value to the nearest multiple of X by doing Math.round(value / X) * X
, and you can restrict a value within [A, B] using Math.min(Math.max(A, value), B)
.
Finally, the min
, max
and step
HTML attributes directly correspond to properties on the JavaScript HTMLInputElement object, which is the object bound to this
inside the event listener.
Combinging all of this together, you get this.
<input type="number" min="1" max="100" step="5" onchange="this.value = Math.min(Math.max(this.min, Math.round(this.value / this.step) * this.step), this.max)">
Note that in your code the min
attribute is 1
which isn't a multiple of 5
, and that tells the browser to accept values in the sequence [1, 6, 11, 16, ...] which breaks our code. If you want multiples of 5, you'll need to make sure the min attribute is a multiple of 5 as well.
All of that JS code inside an HTML attribute is hard to read, so you might want to use a proper event listener at this point, which lets you divide the problem into smaller functions.
function clamp(a, value, b) {
return Math.min(Math.max(a, value), b);
}
function roundTo(multiple, value) {
return Math.round(value / multiple) * multiple;
}
function roundToStepOnChange(event) {
const roundedValue = roundTo(this.step, this.value);
const clampedValue = clamp(this.min, roundedValue, this.max);
this.value = clampedValue;
}
document.getElementById("myInput").addEventListener("change", roundToStepOnChange);
<input id="myInput" type="number" min="5" max="100" step="5">
I set the min attribute to 5 in that example so you can see it running without any issues.