I am trying to set the minimum value of an input type number with jQuery. It is working fine when increasing/decreasing the value using buttons but when entering a custom value with the keyboard, it is messing up.
For instance, min value is set to 5, try to remove 5 and type 8, and it will become 58 instead of 8. type 13 and it will become 513.
CodePudding user response:
Consider the following example.
$(function() {
$.fn.stepDown = function() {
var v = parseInt($(this).val());
if ((v - 1) < parseInt($(this).attr("min"))) {
return false;
}
var s = parseInt($(this).attr("step")) || 1;
$(this).val(v - s);
}
$.fn.stepUp = function() {
var v = parseInt($(this).val());
var s = parseInt($(this).attr("step")) || 1;
$(this).val(v s);
}
$(".number-input button").click(function(e) {
e.preventDefault();
if ($(this).hasClass("plus")) {
$(".number-input input").stepUp();
} else {
$(".number-input input").stepDown();
}
});
$(".number-input input").change(function(e) {
var v = parseInt($(this).val());
var m = parseInt($(this).attr("min"));
if (v < m) {
$(this).val(m);
}
})
});
input[type="number"] {
-webkit-appearance: textfield;
-moz-appearance: textfield;
appearance: textfield;
}
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
-webkit-appearance: none;
}
.number-input {
border: 2px solid #ddd;
display: inline-flex;
}
.number-input,
.number-input * {
box-sizing: border-box;
}
.number-input button {
outline: none;
-webkit-appearance: none;
background-color: transparent;
border: none;
align-items: center;
justify-content: center;
width: 3rem;
height: 3rem;
cursor: pointer;
margin: 0;
position: relative;
}
.number-input button:before,
.number-input button:after {
display: inline-block;
position: absolute;
content: '';
width: 1rem;
height: 2px;
background-color: #212121;
transform: translate(-50%, -50%);
}
.number-input button.plus:after {
transform: translate(-50%, -50%) rotate(90deg);
}
.number-input input[type=number] {
font-family: sans-serif;
max-width: 5rem;
padding: .5rem;
border: solid #ddd;
border-width: 0 2px;
font-size: 2rem;
height: 3rem;
font-weight: bold;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
<div >
<button></button>
<input type="number" value="59" min="5" />
<button ></button>
</div>
</form>
If a User enters 3
or 1
and then moves away from field, it will be changed to the Min. The user can still enter 41
or 10
manually as the check will not happen until change
is triggered.
Also, input
elements always contain a String value. Casting it to an integer can help ensure proper comparisons and Math.
CodePudding user response:
When you delete it, the next time you press a key, before it is updated, you are calling
$(this).val(Math.min(10000, Math.max(5, $(this).val())));
which is effectively:
console.log(Math.min(10000, Math.max(5, '')))
or, 5. So it becomes 5, then gets the next number appended, so then when you press e.g. 8, it becomes 58.
A simple fix is:
if ($(this).val() !== '') {
$(this).val(Math.min(10000, Math.max(5, $(this).val())));
}
$('input[type=number].cart__product-qty').on('mouseup keydown', function() {
if ($(this).val() !== '') {
$(this).val(Math.min(10000, Math.max(5, $(this).val())));
}
});
// To prevent the button trigger the form submission
$('form').on('click', 'button:not([type="submit"])', function(e) {
e.preventDefault();
})
input[type="number"] {
-webkit-appearance: textfield;
-moz-appearance: textfield;
appearance: textfield;
}
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
-webkit-appearance: none;
}
.number-input {
border: 2px solid #ddd;
display: inline-flex;
}
.number-input,
.number-input * {
box-sizing: border-box;
}
.number-input button {
outline: none;
-webkit-appearance: none;
background-color: transparent;
border: none;
align-items: center;
justify-content: center;
width: 3rem;
height: 3rem;
cursor: pointer;
margin: 0;
position: relative;
}
.number-input button:before,
.number-input button:after {
display: inline-block;
position: absolute;
content: '';
width: 1rem;
height: 2px;
background-color: #212121;
transform: translate(-50%, -50%);
}
.number-input button.plus:after {
transform: translate(-50%, -50%) rotate(90deg);
}
.number-input input[type=number] {
font-family: sans-serif;
max-width: 5rem;
padding: .5rem;
border: solid #ddd;
border-width: 0 2px;
font-size: 2rem;
height: 3rem;
font-weight: bold;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
<div >
<button onclick="this.parentNode.querySelector('input[type=number].cart__product-qty').stepDown()"></button>
<input type="number" value="5" min="5">
<button onclick="this.parentNode.querySelector('input[type=number].cart__product-qty').stepUp()" ></button>
</div>
</form>
CodePudding user response:
I think the problem may be that the code checking for the minimum value is running on each keydown
event rather than after input is complete. Try making the following modification:
Change: mouseup keydown
to mouseup blur
in your jQuery event handler.
Demo:
$('input[type=number].cart__product-qty').on('mouseup blur', function () {
$(this).val(Math.min(10000, Math.max(5, $(this).val())));
});
$('form').on('click', 'button:not([type="submit"])', function(e){
e.preventDefault();
})
input[type="number"] {
-webkit-appearance: textfield;
-moz-appearance: textfield;
appearance: textfield;
}
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
-webkit-appearance: none;
}
.number-input {
border: 2px solid #ddd;
display: inline-flex;
}
.number-input,
.number-input * {
box-sizing: border-box;
}
.number-input button {
outline:none;
-webkit-appearance: none;
background-color: transparent;
border: none;
align-items: center;
justify-content: center;
width: 3rem;
height: 3rem;
cursor: pointer;
margin: 0;
position: relative;
}
.number-input button:before,
.number-input button:after {
display: inline-block;
position: absolute;
content: '';
width: 1rem;
height: 2px;
background-color: #212121;
transform: translate(-50%, -50%);
}
.number-input button.plus:after {
transform: translate(-50%, -50%) rotate(90deg);
}
.number-input input[type=number] {
font-family: sans-serif;
max-width: 5rem;
padding: .5rem;
border: solid #ddd;
border-width: 0 2px;
font-size: 2rem;
height: 3rem;
font-weight: bold;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
<div >
<button onclick="this.parentNode.querySelector('input[type=number].cart__product-qty').stepDown()"></button>
<input type="number" value="59" min="5">
<button onclick="this.parentNode.querySelector('input[type=number].cart__product-qty').stepUp()" ></button>
</div>
</form>
Notice that now when you leave the <input />
via a click outside or tab out, the validation rule runs once and the input is correctly updated.