0

I have a calculator that get values from inputs and then performs some calculations. Each input is a type="number" field. Everything works fine, but if you use . or - then the calculator works incorrectly. I see an empty value in console, but it works fine with ,. I added pattern="\d+(,\d{2})?", but maybe I did something wrong, but this didn't help?

I need to forbid input . and -, and it would be great if someone explain how to cut value to two characters after , to make it look like the price.

Thank you

Here is my example:

$('.calculator-button').on('click', function() {
  var calculator = {
    priceGbo: $('#price_gbo').val(),
    priceFuel: $('#price_fuel').val(),
    priceGas: $('#price_gas').val(),
    priceMile: $('#expenses_mile').val(),
    priceDay: $('#expenses_day').val()
  };

  var everydayEconomy = calculator.priceDay * (calculator.priceMile / 100) *
                        (calculator.priceFuel - calculator.priceGas * 1.1);
  var fiveYears = everydayEconomy * 1825;
  var feedbackTime = calculator.priceGbo / everydayEconomy;

  $('#everyday_economy').text(everydayEconomy.toFixed(0));
  $('#fiveYears_economy').text(fiveYears.toFixed(0));
  $('#feedback_time').text(feedbackTime.toFixed(0));
});
.call-modal {
  width: 380px;
  height: 48px;
  background: #ffc107;
  color: black;
  font-size: 18px;
  font-family: "Pt Sans Bold";
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
     -ms-flex-align: center;
         align-items: center;
 -webkit-box-pack: center;
     -ms-flex-pack: center;
         justify-content: center;
  cursor: pointer;
  margin: 0.667em 0;
}
/** Added to reduce clutter. */
.calculator-inputs-left-row__text,
.calculator-results-item__text {
  display: inline-block;
  width: 13em;
  font-weight: bold;
}
.calculator-inputs-left-row__text:after,
.calculator-results-item__text:after {
  content : ': ';
}
.calculator-inputs-left-row__input,
.calculator-results-item__result {
  display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="calculator-inputs-left">
  <div class="calculator-inputs-left-row">
    <div class="calculator-inputs-left-row__text">Price GBO ($)</div>
    <div class="calculator-inputs-left-row__input">
      <input type="number" pattern="\d+(,\d{2})?" class="calculator-input" id="price_gbo" min="0" value="">
    </div>
  </div>
  <div class="calculator-inputs-left-row">
    <div class="calculator-inputs-left-row__text">Price fuel ($)</div>
    <div class="calculator-inputs-left-row__input">
      <input type="number" class="calculator-input" id="price_fuel" min="0" value="">
    </div>
  </div>
  <div class="calculator-inputs-left-row">
    <div class="calculator-inputs-left-row__text">Price gas ($)</div>
    <div class="calculator-inputs-left-row__input">
      <input type="number" class="calculator-input" id="price_gas" min="0" value="">
    </div>
  </div>
  <div class="calculator-inputs-left-row">
    <div class="calculator-inputs-left-row__text">Consumption on 100 km (l)</div>
    <div class="calculator-inputs-left-row__input">
      <input type="number" class="calculator-input" id="expenses_mile" min="0" value="">
    </div>
  </div>
  <div class="calculator-inputs-left-row">
    <div class="calculator-inputs-left-row__text">Average daily mileage (km)</div>
    <div class="calculator-inputs-left-row__input">
      <input type="number" class="calculator-input" id="expenses_day" min="0" value="">
    </div>
  </div>
</div>
<div class="call-modal calculator-button">Get result</div>
<div class="calculator-line"></div>
<div class="calculator-results">
  <div class="calculator-results-item">
    <div class="calculator-results-item__text">Daily savings ($)</div>
    <div class="calculator-results-item__result">
      <span id="everyday_economy"></span>
    </div>
  </div>
  <div class="calculator-results-item">
    <div class="calculator-results-item__text">For 5 years of operation ($)</div>
    <div class="calculator-results-item__result">
      <span id="fiveYears_economy"></span>
    </div>
  </div>
  <div class="calculator-results-item">
    <div class="calculator-results-item__text">Payback period (days)</div>
    <div class="calculator-results-item__result">
      <span id="feedback_time"></span>
    </div>
  </div>
</div>
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
Yaroslav Saenko
  • 517
  • 2
  • 7
  • 21

3 Answers3

0

You might want to parse the input using parseFloat:

var calculator = {
  priceGbo: parseFloat($('#price_gbo').val()),

a calculation like "12"*"5.0" will work in Javascript and yield 60, while "12"*"5,0" will return NaN.

Parsing the strings as floating point numbers fixes things:

parseFloat("12")*parseFloat("5,0") == 60 // true
Leonhardt Wille
  • 557
  • 5
  • 20
0

To actually answer the question:

<input type="number" pattern="^(?:\d|[^.e-])+$"/>

input validation will only work if you use a <form onSubmit="javascript:doCalculation()"> element with an <input type="submit"/> button. Your onSubmit handler would only be called when validation is successful.

An onClick handler of some button will always be able to read the current value without any validation.

https://www.w3schools.com/tags/att_input_pattern.asp

https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_input_pattern

Leonhardt Wille
  • 557
  • 5
  • 20
  • While it's a nice idea, it's also worth noting that Safari doesn't support the pattern attribute at all, which can leave a noticeable gap in browser support. – DBS Apr 06 '18 at 16:35
  • good point, @DBS - however w3schools states Safari 10.1 supports it (since 3/2017). – Leonhardt Wille Apr 12 '18 at 16:10
  • 1
    You are correct, I think I must have misread a support table. Sorry about that. – DBS Apr 12 '18 at 16:27
0

Characters such as , are not allowed inside the number field. Please review the specs for the W3C floating-point number datatype.


You need to do a couple things:

  1. Wrap your inputs in a form to utilize native submit validation
  2. Make the form return false on submission so that it does not navigate from the page.
  3. Change all your inputs to a text field with a pattern. I added that logic at the very top.
  4. Use a parser function to normalize all the numbers into proper floating-point numbers.

The example below shows all of this in action.

// Change number fields to text with number validation.
// See: https://stackoverflow.com/questions/13412204/localization-of-input-type-number
$('.calculator-input').each(function() {
  $(this).attr('type', 'text').attr('pattern', '\\d+(,\\d{2})?');
});

$('.calculator-button').on('click', function() {
  var calculator = {
    priceGbo: currencyParser($('#price_gbo').val()),
    priceFuel: currencyParser($('#price_fuel').val()),
    priceGas: currencyParser($('#price_gas').val()),
    priceMile: currencyParser($('#expenses_mile').val()),
    priceDay: currencyParser($('#expenses_day').val())
  };

  var everydayEconomy = calculator.priceDay * (calculator.priceMile / 100) *
                        (calculator.priceFuel - calculator.priceGas * 1.1);
  var fiveYears = everydayEconomy * 1825;
  var feedbackTime = calculator.priceGbo / everydayEconomy;

  $('#everyday_economy').text(everydayEconomy.toFixed(0));
  $('#fiveYears_economy').text(fiveYears.toFixed(0));
  $('#feedback_time').text(feedbackTime.toFixed(0));
});

// See: https://gist.github.com/leodutra/3057153
function currencyParser(str) {
  str = (str + '').replace(/[^\d,.-]/g, '');
  var sign = str.charAt(0) === '-' ? '-' : '+';
  var minor = str.match(/[.,](\d+)$/);
  str = str.replace(/[.,]\d*$/, '').replace(/\D/g, '');
  return Number(sign + str + (minor ? '.' + minor[1] : ''));
}
.call-modal {
  width: 380px;
  height: 48px;
  background: #ffc107;
  color: black;
  font-size: 18px;
  font-family: "Pt Sans Bold";
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
  -webkit-box-pack: center;
      -ms-flex-pack: center;
          justify-content: center;
  cursor: pointer;
  margin: 0.667em 0;
}
/** Added to reduce clutter. */
.calculator-inputs-left-row__text,
.calculator-results-item__text {
  display: inline-block;
  width: 13em;
  font-weight: bold;
}
.calculator-inputs-left-row__text:after,
.calculator-results-item__text:after {
  content : ': ';
}
.calculator-inputs-left-row__input,
.calculator-results-item__result {
  display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form onsubmit="return false">
  <div class="calculator-inputs-left">
    <div class="calculator-inputs-left-row">
      <div class="calculator-inputs-left-row__text">Price GBO ($)</div>
      <div class="calculator-inputs-left-row__input">
        <input type="number" pattern="\d+(,\d{2})?" class="calculator-input" id="price_gbo" min="0" value="">
      </div>
    </div>
    <div class="calculator-inputs-left-row">
      <div class="calculator-inputs-left-row__text">Price fuel ($)</div>
      <div class="calculator-inputs-left-row__input">
        <input type="number" class="calculator-input" id="price_fuel" min="0" value="">
      </div>
    </div>
    <div class="calculator-inputs-left-row">
      <div class="calculator-inputs-left-row__text">Price gas ($)</div>
      <div class="calculator-inputs-left-row__input">
        <input type="number" class="calculator-input" id="price_gas" min="0" value="">
      </div>
    </div>
    <div class="calculator-inputs-left-row">
      <div class="calculator-inputs-left-row__text">Consumption on 100 km (l)</div>
      <div class="calculator-inputs-left-row__input">
        <input type="number" class="calculator-input" id="expenses_mile" min="0" value="">
      </div>
    </div>
    <div class="calculator-inputs-left-row">
      <div class="calculator-inputs-left-row__text">Average daily mileage (km)</div>
      <div class="calculator-inputs-left-row__input">
        <input type="number" class="calculator-input" id="expenses_day" min="0" value="">
      </div>
    </div>
  </div>
  <button type="submit" class="call-modal calculator-button">Get result</button>
</form>
<div class="calculator-line"></div>
<div class="calculator-results">
  <div class="calculator-results-item">
    <div class="calculator-results-item__text">Daily savings ($)</div>
    <div class="calculator-results-item__result">
      <span id="everyday_economy"></span>
    </div>
  </div>
  <div class="calculator-results-item">
    <div class="calculator-results-item__text">For 5 years of operation ($)</div>
    <div class="calculator-results-item__result">
      <span id="fiveYears_economy"></span>
    </div>
  </div>
  <div class="calculator-results-item">
    <div class="calculator-results-item__text">Payback period (days)</div>
    <div class="calculator-results-item__result">
      <span id="feedback_time"></span>
    </div>
  </div>
</div>
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132