mhpcc
mhpcc

Reputation: 145

html <input type="text" /> number-only with min and max value

I'm trying to get the min="" and max="" attributes working on a number only input. Using <input type="number"> is out of the question due to terrible browser support for localization (dots should be thousand seperators, comma as decimal seperator, in input as well as in submit). Optimally, upon form submit of every form, it would check for those certain fields if the number follows the pattern and is in the correct range, just like it would do natively for a type="number" input.

Alternatively, if it's possible or easier, I'm also open to using <input type="number" /> as long as pattern, currency signs and most importantly, commas are accepted in BOTH the value="123,12", the user input AND the value submitted to the server.

So far, I use pattern="-?(\d+|\d{1,3}(\.\d{3})*)(,\d+)?" which already validates the input except for min and max values.

Expected behaviour is that on a <input type="text" pattern"-?(\\d+|\\d{1,3}(\\.\\d{3})*)(,\\d+)?" min="0" max="1500" /> it would let me input any value I want, but when submitting the form, check if the numerically parsed value of the field (omitting currency signs or dots, understanding commas as decimal) is in the range between 0 and 1500. Optimally, but this doesn't matter as much, I'd also like the increment and decrement arrows with a step="0.01" such as for type="number" inputs.

Sadly, I'm completely out of ideas on how to implement this on a per-field basis and not run global javascript on each form submisssion button, preventing the default if not every input matches the criteria. But even if I did that, how would I go about displaying the correct (localized) warnings that type="number" would give me?

Upvotes: 0

Views: 6116

Answers (1)

LIGHT
LIGHT

Reputation: 5712

$("input[data-type='currency']").on({
    keyup: function() {
      formatCurrency($(this));
    },
    blur: function() { 
      validateCurrency($(this));
      formatCurrency($(this), "blur");
    }
});

function validateCurrency(input){
    var c = parseFloat(input.val().replace(/\,|$/g,'').replace('$',''));
    if(c<input.attr('min')){
        input.val(input.attr('min'));
    }else if(c>input.attr('max')){
        input.val(input.attr('max'));
    }
}
function formatNumber(n) {
  // format number 1000000 to 1,234,567
  return n.replace(/\D/g, "").replace(/\B(?=(\d{3})+(?!\d))/g, ",")
}


function formatCurrency(input, blur) {
  // appends $ to value, validates decimal side
  // and puts cursor back in right position.
  
  // get input value
  var input_val = input.val();
  
  // don't validate empty input
  if (input_val === "") { return; }
  
  // original length
  var original_len = input_val.length;

  // initial caret position 
  var caret_pos = input.prop("selectionStart");


  // check for decimal
  if (input_val.indexOf(".") >= 0) {

    // get position of first decimal
    // this prevents multiple decimals from
    // being entered
    var decimal_pos = input_val.indexOf(".");

    // split number by decimal point
    var left_side = input_val.substring(0, decimal_pos);
    var right_side = input_val.substring(decimal_pos);

    // add commas to left side of number
    left_side = formatNumber(left_side);

    // validate right side
    right_side = formatNumber(right_side);
    
    // On blur make sure 2 numbers after decimal
    if (blur === "blur") {
      right_side += "00";
   }
    
    // Limit decimal to only 2 digits
    right_side = right_side.substring(0, 2);

    // join number by .
    input_val = "$" + left_side + "." + right_side;

  } else {
    // no decimal entered
    // add commas to number
    // remove all non-digits
    input_val = formatNumber(input_val);
    input_val = "$" + input_val;
    
    // final formatting
    if (blur === "blur") {
      input_val += ".00";
    }
  }
  
  // send updated string to input
  input.val(input_val);

  // put caret back in the right position
  var updated_len = input_val.length;
  caret_pos = updated_len - original_len + caret_pos;
  input[0].setSelectionRange(caret_pos, caret_pos);
}
input {
  border: 2px solid #333;
  border-radius: 5px;
  color: #333;
  font-size: 32px;
  margin: 0 0 20px;
  padding: .5rem 1rem;
  width: 50%;

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" name="currency-field" id="currency-field" pattern="^\$\d{1,3}(,\d{3})*(\.\d+)?$" value="" data-type="currency" min="1000" max="1000000" placeholder="$200,000.00">
Minimum: 1000, Maximum: 1,000,000

Code by: Wade Williams @559wade

Tweaks: I just added validateCurrency() function and executed it on blur event to check for min and max

Upvotes: 1

Related Questions