Nathan Long
Nathan Long

Reputation: 126122

How can I use jQuery to prevent a user from typing too many decimal places?

I'm trying to write a jQuery plugin to prevent users from typing numbers with more than 2 decimal places. Specifically:

Here's the problem I'm running into:

How can I do this?

Upvotes: 4

Views: 3223

Answers (2)

Nathan Long
Nathan Long

Reputation: 126122

Solution that works for my purposes

Here's what I came up with.

Pros

  • Excessive decimal places do not appear at all (as opposed to appearing and being immediately erased)
  • User also cannot enter multiple decimals

Cons

This solution depends on 2 other jQuery plugins in this, but I already had them in my project anyway.

  • I'm using the caret() function that's part of jQuery.maskedInput to determine where in the input box the user is typing.
  • I'm already using 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.)

The code

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

pete
pete

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

Related Questions