Search code examples
jquerymathcalculatoradditionsubtraction

Jquery dimensions calculator


I have a friend who works for a company selling radiator covers and have been asked to add a dimension calculator to their site so people can add their measurements and extras and purchase online.

The meat and potatoes of the code is working but for some reason the price is being updated in the wrong sides of the decimal point.

Here is my example code on jsfiddle https://jsfiddle.net/AndyDyas/tw62Lzop/48/

<div class="wrapper">
    <label for="a">Width:</label>
        <input type="number" name="a" id="a" value="1000" placeholder="1000"  /><br>
    <label for="b">Height:</label>
        <input type="number" name="b" id="b" value="800" placeholder="800" /><br>
    <label for="c">Depth:</label>
        <input type="number" name="c" id="c" value="15" placeholder="15" /><br>   
    <label for="d">Colour:</label>
        <select name="colour" id="d">
          <option value="0">Select</option>
          <option value="-15">Primed (-£15)</option>
          <option value="50">Gloss (+£50)</option>
          <option value="40">Own Colour (£40)</option>
        </select> <br> 
    <label for="e">Grille:</label>
        <select name="grille" id="e">
          <option value="0">Select</option>
          <option value="40">Slats (+£40)</option>
          <option value="75">Regency Brass (+£75)</option>
          <option value="150">Regency Antique / Chrome (+£150)</option>
          <option value="40">Gold / Silver SAA (+£40)</option>
        </select> <br>           
    <label for="total">Result:</label>
        <input type="text" name="total" id="total" value="260.00"  />
    </div>
    <script>
      jQuery(document).ready(function() {
        var price = jQuery('#total').val();
        function compute() {
          var a = parseFloat(jQuery('#a').val() - jQuery('#a').attr("placeholder"));
          var b = parseFloat(jQuery('#b').val() - jQuery('#b').attr("placeholder"));
          var c = parseFloat(jQuery('#c').val() - jQuery('#c').attr("placeholder"));
          var d = parseFloat(jQuery('#d').val()).toFixed(2);
          var e = parseFloat(jQuery('#e').val()).toFixed(2);
          var total = parseFloat(a) + parseFloat(b) + parseFloat(c) + parseFloat(d) + parseFloat(e) + parseFloat(price);
          jQuery('#total').val(parseFloat(total).toFixed(2));
          //alert(a);
        }
        jQuery('#a, #b, #c, #d, #e').change(compute);        
      });;
    </script>
</div>

What needs to happen is for every extra mm in the width/height/depth 10p needs to be added to the price but for some reason it's adding it on the wrong side of the decimal point (adding £1 instead of 10p) and the opposite for the colour and grille which is in pounds.

Hope this load of mess makes sense and i would be very very grateful for some help with this.

Cheers

Andy


Solution

  • I took the opportunity to rewrite the code to be more extensible and flexible

    • made an object to hold the values and the price changes
    • look up these settings on load to set the defaults
    • validate the required fields on change
    • cast the field values to numbers

    // this object is the basis for all fields
    const prices = {
      "base" : 260,
      "width":  { "min": 1000, "extra": 0.1  },
      "height": { "min":  800, "extra": 0.15 },
      "depth":  { "min": 15,   "extra": 0    } // correct?
    };
    // helper function to cast to number from string
    const toNum = str => isNaN(str) || str.trim() === "" ? 0 : +str;
    
    
    const compute = e => {
      if (e) e.target.reportValidity(); // show error if field is emptied
      let width = toNum($('#width').val()),
         height = toNum($('#height').val()),
          depth = toNum($('#depth').val()),
         colour = toNum($('#colour').val()),
         grille = toNum($('#grille').val()),
      widthPrice  = (width - prices["width"].min)*prices["width"].extra,
      heightPrice  = (height - prices["height"].min)*prices["height"].extra,
      depthPrice  = (depth - prices["depth"].min)*prices["depth"].extra,
      total = prices["base"] + widthPrice + heightPrice + depthPrice + colour + grille;
      if (total < prices["base"]) total = prices["base"]; // not possible to get less than base price
      $('#total').val(total.toFixed(2));
    };
    
    
    $(function() {
      // setting the defaults based on the object at the top
      ["width","height","depth"]
        .forEach(field => ["min","placeholder","value"]
          .forEach(attr => $('#'+field).attr(attr,prices[field].min))
      )    
          
      compute();
      $('#computeDiv').on("input", compute);
    });
    label {
      display: inline-block;
      width: 140px;
      text-align: right;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    
    <p>The basic unit is 1000mm wide by 800mm tall and costs £260.00</p>
    <p>Every extra 1mm in width is an additional 10 pence per mm and every extra 1mm in height is an extra 15 pence per mm.</p>
    <p>The dropdowns are simple extra features at fixed costs there is only the width and height that are dynamic.</p>
    <p>So a unit that is 1001mm x 801mm would cost £260.25 (£260 + 10p + 15p) </p>
    
    <div id="computeDiv">
      <label for="width">Width (mm):</label> <input type="number" name="width" id="width" value="" required/><br>
      <label for="height">Height (mm):</label> <input type="number" name="height" id="height" value="" required /><br>
      <label form="depth">Depth (mm):</label> <input type="number" name="depth" id="depth" value="" required /><br>
      <label for="colour">Colour:</label>
      <select name="colour" id="colour">
        <option value="0">Select</option>
        <option value="-15">Primed (-£15)</option>
        <option value="50">Gloss (+£50)</option>
        <option value="40">Own Colour (£40)</option>
      </select><br>
      <label for="grille">Grille:</label>
      <select name="grille" id="grille">
        <option value="0">Select</option>
        <option value="40">Slats (+£40)</option>
        <option value="75">Regency Brass (+£75)</option>
        <option value="150">Regency Antique / Chrome (+£150)</option>
        <option value="40">Gold / Silver SAA (+£40)</option>
      </select><br>
      <label>Total:</label>
      <input type="text" name="total" id="total" value="0.00" readonly />
    </div>