mikedevp
mikedevp

Reputation: 25

Cost Calculator using JavaScript - Advanced

So I have a HTML form which has two dropdown menus and a button. One dropdown menu has 'package type' which consists of 'Gold', 'Silver' and 'Bronze'. The second dropdown menu has 'months' with 12 options (for up to 12 months) and then a calculate button.

Now, this is the bit I hope I can explain well...

If you select 'Silver', and '1 month', it will cost £150.00.

If you select 'Silver', and '2 months', it will cost £225.00.

If you select 'Silver', and '3 months', it will cost £300.00.

And so on (up to 12 months). So the logic for the above is £150.00 for the first month, and then £75 for additional months.

But if you decide you want to have a 'Gold' package, it will be as follows:

If you select 'Gold', and '1 month', it will cost £199.00.

If you select 'Gold', and '2 months', it will cost £298.50.

If you select 'Gold', and '3 months', it will cost £398.00.

And so on (up to 12 months). So the logic for the above is £199.99 for the first month, and then £99.50 for additional months.

And similar for 'Bronze' too, except 1 month is £75.00, 2 months is £112.50 (logic is £75.00 for first month, and £37.50 for additional months).

I hope this makes sense? Below is the HTML for the form, which I know does not work, but this is just to try and explain...

<form name="costcalculator">
  <div class="package-type">
<select name="packageType" id="packageType">
  <option value="199.00" label="Gold">Gold</option>
  <option value="150.00" label="Silver">Silver</option>
  <option value="75.00" label="Bronze">Bronze</option>
</select>
  </div>

  <div class="months">
<select name="months" id="months-bronze">
  <option value="£75.00" label="1 month">1 month Bronze</option>
  <option value="£112.50" label="2 months">2 months Bronze</option>
</select>
</div>

<div class="months">
<select name="months" id="months-silver">
  <option value="£150.00" label="1 month">1 month Silver</option>
  <option value="£225.00" label="2 months">2 months Silver</option>
</select>
</div>

<div class="months">
<select name="months" id="months-gold">
  <option value="£199.00" label="1 month">1 month Gold</option>
  <option value="£298.50" label="2 months">2 months Gold</option>
</select>
</div>

<button type="button" onclick="calculatePrice();showDiv();">Calculate</button>
</form>

What I currently have (that works), is the following, but it doesn't do what I need it to do, this just has the cost hardcoded in, so regardless of the package type, the cost will be the same (except for the initial cost being different for each package):

<form name="costcalculator">
  <div class="package-type">
<select name="packageType" id="packageType">
  <option value="199.00" label="Gold">Gold</option>
  <option value="150.00" label="Silver">Silver</option>
  <option value="75.00" label="Bronze">Bronze</option>
</select>
  </div>

  <div class="months">
<select name="months" id="months">
  <option value="100.00" label="1 month">1 month</option>
  <option value="200.75" label="2 months">2 months</option>
  <option value="275.25" label="3 months">3 months</option>
  <option value="349.00" label="4 months">4 months</option>
  <option value="369.99" label="5 months">5 months</option>
  <option value="450.00" label="6 months">6 months</option>
</select>
</div>

<button type="button" onclick="calculatePrice();showDiv();">Calculate</button>
</form>

And the JavaScript as follows:

function calculatePrice(costcalculator){
  var elt = document.getElementById("packageType");
  var package = elt.options[elt.selectedIndex].value;

  var elt = document.getElementById("months");
  var months = elt.options[elt.selectedIndex].value;

  package = parseFloat(package);
  months = parseFloat(months);

  var total = package+months; 

  document.getElementById("TotalPrice").value=total;
}

So I thought I was nearly there with the working code above, but the more I get into it, the more I realise it's way off.

It just needs a way that when the user selects the package type in the first dropdown menu, then the second dropdown menu containing the months will (behind the scenes) have populated the new costs immediately before the user selects number of months, and then if the user then decides to select a different package to the last one, the second dropdown menu will refresh again but with the different costs in the background.

Upvotes: 2

Views: 9134

Answers (2)

user3307073
user3307073

Reputation:

Or, you may go, like:

//data model
var membershipPlans = {
  silver: {'1mo': 150, '2mo': 225, '3mo': 300},
  gold: {'1mo': 199, '2mo': 298.5, '3mo': 398}
};
//don't punish me for that with downvotes , please :)
Array.prototype.unique = function() {
  const resArr = [];
  this.forEach(entry => {
    if(resArr.indexOf(entry) == -1) resArr.push(entry);
  })
  return resArr;
};
//populate the view with possible options
const inputFields = {
  package: document.getElementById('package'),
  duration: document.getElementById('duration')
};
const cost = document.getElementById('cost');
inputFields.package.innerHTML = Object.keys(membershipPlans).sort().reduce((options, option) => options+=`<option value="${option}">${option}</option>`,'<option value="" selected disabled></option>');
inputFields.duration.innerHTML = Object.values(membershipPlans).map(entry => Object.keys(entry)).flat().unique().reduce((options, option) => options+=`<option value="${option}">${option}</option>`,'<option value="" selected disabled></option>');
//listen for input changes and display the cost
Object.values(inputFields).forEach(inputField => {
  inputField.addEventListener('change', ()=> 
    cost.innerHTML =  Object.values(inputFields).every(inputField => inputField.value !='') ? membershipPlans[inputFields.package.value][inputFields.duration.value]+'&nbsp&pound' : '-&nbsp&pound')
});
<div id="wrapper">
<span>Pick your </span>
<br>
<label>package:</label>
<select id="package" class="calcInput"></select>
<label>duration:</label>
<select id="duration" class="calcInput"></select>
<br>
<span>Your cost is:</span>
<br>
<span id="cost">-&nbsp&pound</span>
</div>

Upvotes: 0

HaukurHaf
HaukurHaf

Reputation: 13816

Here's a simple solution using a simple data structure as per the comment from 04FS. The data structure has the package name as the key, for easy lookup. It has the base price (for the first month) and then the price for additional months, so the total price can be easily calculated.

HTML markup:

<form name="costcalculator">
  <div class="package-type">
    <select name="packageType" id="packageType" onchange="setMonths(this.value)">
      <option value="gold">Gold</option>
      <option value="silver">Silver</option>
      <option value="bronze">Bronze</option>
    </select>
  </div>

  <div class="months">
    <select name="months" id="months">
      <option value="1">1 month</option>
      <option value="2">2 months</option>
      <option value="3">3 months</option>
      <option value="4">4 months</option>
      <option value="5">5 months</option>
      <option value="6">6 months</option>
      <option value="7">7 months</option>
      <option value="8">8 months</option>
      <option value="9">9 months</option>
      <option value="10">10 months</option>
      <option value="11">11 months</option>
      <option value="12">12 months</option>
    </select>
  </div>

  <button type="button" onclick="calculatePrice()">Calculate</button>
  <div id="price"></div> 
</form>

Javascript code:

var costs = {
    'gold': {'basePrice': 199.99, 'pricePerMonth' : 99.5, 'maxMonths': 12},
    'silver': {'basePrice': 150, 'pricePerMonth' : 75, 'maxMonths': 12},
    'bronze': {'basePrice': 75, 'pricePerMonth' : 37.5, 'maxMonths': 2}
};

function setMonths(package)
{
    var maxMonths = costs[package].maxMonths;
    document.getElementById("months").innerHTML = ''; // Clear all options
    for (var i = 1; i<=maxMonths; i++){
       var opt = document.createElement('option');
       opt.value = i;
       opt.innerHTML = i +  (i > 1 ? ' months' : ' month');
       document.getElementById('months').appendChild(opt);
    }
}

function calculatePrice()
{
  var package = document.getElementById('packageType').value;
  var months = document.getElementById('months').value;
  var price = costs[package].basePrice + (costs[package].pricePerMonth * (months - 1));
  document.getElementById('price').innerHTML = price.toFixed(2);
}

Working sample:

https://jsfiddle.net/td3j5frn/

Upvotes: 1

Related Questions