Reputation: 126122
I'm trying to write a jQuery plugin to prevent users from typing numbers with more than 2 decimal places. Specifically:
12
and the user types 3
at the end, it should work.12.34
and the user types 1
at the end, nothing should happen.12.34
and the user types 1
at the beginning, it should work.Here's the problem I'm running into:
keypress
, I do not know what the "proposed new value" is; $(this).val()
is the value before the user pressed the key, and I don't know where in the input field the user is typing.keyup
, $(this).val()
is the new value, but it has already appeared in the text input. I can erase it if it has too many decimal places, but it looks glitchy.How can I do this?
Upvotes: 4
Views: 3223
Reputation: 126122
Here's what I came up with.
This solution depends on 2 other jQuery plugins in this, but I already had them in my project anyway.
caret()
function that's part of jQuery.maskedInput
to determine where in the input box the user is typing.jQuery.keyfilter
on this input to ensure that only 1-9
and .
are allowed to be typed in it. (It only considers individual keystrokes, though, not the resulting input contents.)jQuery.fn.limitDecimalPlaces = function (maxPlacesArg) {
$(this).each(function() {
var maxPlaces, presetValue;
if (maxPlacesArg) {
maxPlaces = maxPlacesArg;
} else {
presetValue = $(this).attr('value');
// If the value attribute has a decimal in it...
if (presetValue.indexOf('.') !== -1) {
// ... assume it has the correct number of places
maxPlaces = presetValue.split('.')[1].length;
} else {
// Sensible default
maxPlaces = 2;
}
}
$(this).bind("keypress", function(e) {
var currentVal, cursorIsAfterDecimal, hasMaxDecimalPlaces, inputHasDecimal, keystrokeIsDecimal;
currentVal = $(this).val();
inputHasDecimal = currentVal.indexOf('.') !== -1;
if (inputHasDecimal) {
// Booleans
keystrokeIsDecimal = String.fromCharCode(e.which) === '.';
hasMaxDecimalPlaces = athena.format.hasNDecimalPlaces(currentVal, maxPlaces);
cursorIsAfterDecimal = ($(this).caret().begin) > (currentVal.lastIndexOf('.'));
if (keystrokeIsDecimal || (hasMaxDecimalPlaces && cursorIsAfterDecimal)) {
e.preventDefault();
}
}
});
});
return $(this);
}
The supporting function:
hasNDecimalPlaces = function (number, places) {
fixed = parseFloat(number).toFixed(places);
return number.toString() === fixed;
};
Upvotes: 2
Reputation: 25091
Mebbe this?
jQuery.fn.limitDecimalPlaces = function(maxPlaces) {
$(this).on('keyup', function(e) {
integer = e.target.value.split('.')[0],
mantissa = e.target.value.split('.')[1];
if (typeof mantissa === 'undefined') {
mantissa = '';
}
if (mantissa.length > maxPlaces) {
e.target.value = integer + '.' + mantissa.substring(0, maxPlaces);
}
});
}
Tested and working at http://jsfiddle.net/vdZfH/2/
Upvotes: 3