skip to Main Content

I am unable to find a way to total sales.

//Quarts 1
function updateOrder1() {
  const X = 13;
  var Y = document.getElementById("Quarts");
  var value = Y[Y.selectedIndex].text;
  var Z = value * X;
  document.getElementById("total1").value = "$" + Z.toFixed(2)
}
//Pints 2  
function updateOrder2() {
  const X = 8;
  var Y = document.getElementById("Pints");
  var value = Y[Y.selectedIndex].text;
  var Z = value * X;
  document.getElementById("total2").value = "$" + Z.toFixed(2)
}
<table border=1 px>
  <tr>
    <td><b>Quarts</b></td>
    <td>
      <form>
        <select id="Quarts" onchange="updateOrder1();">
          <option>Select</option>
          <option>1</option>
          <option>2</option>
          <option>3</option>
          <option>4</option>
          <option>5</option>
        </select>
    </td>
    
    <td width="3%">
      <input type="text" id="total1" name="total1" value="0" readonly="readonly" />
    </td>
  </tr>

  <tr>
    <td><b>Pints</b></td>
    <td>
      <form>
        <select id="Pints" onchange="updateOrder2();">
          <option>Select</option>
          <option>1</option>
          <option>2</option>
          <option>3</option>
          <option>4</option>
          <option>5</option>
        </select>
    </td>
    <td>
      <input type="text" id="total2" name="total2" value="0" readonly="readonly" />
    </td>
  </tr>

  <tr>
    <td></td>
    <td>
      Total
      </div>
    </td>
    <td></td>
  </tr>
</table>

3

Answers


  1. React to change events of your select boxes inside the table and use Array::reduce to calculate the total, then insert it into the total cell:

    //Quarts 1
    
    document.querySelector('table').addEventListener('change', e => {
    
       // find all cells with totals in the table
       const totalCells = e.target.closest('table').querySelectorAll('[name^=total]');
    
       // calc sum of the totals with parsing a currencty into a float number
       const total = [...totalCells].reduce((sum, elem) => sum + parseFloat(elem.value.match(/[d.]+/)?.[0] || 0), 0);
       
       orderTotal.textContent = '$' + total.toFixed(2);
       
    
    });
    
    function updateOrder1() {
      const X = 13;
      var Y = document.getElementById("Quarts");
      var value = Y[Y.selectedIndex].text;
      var Z = value * X;
      document.getElementById("total1").value = "$" + (Z||0).toFixed(2)
    }
    //Pints 2  
    function updateOrder2() {
      const X = 8;
      var Y = document.getElementById("Pints");
      var value = Y[Y.selectedIndex].text;
      var Z = value * X;
      document.getElementById("total2").value = "$" + (Z||0).toFixed(2)
    }
    <table border=1 px>
      <tr>
        <td><b>Quarts</b></td>
        <td>
          <form>
            <select id="Quarts" onchange="updateOrder1();">
              <option>Select</option>
              <option>1</option>
              <option>2</option>
              <option>3</option>
              <option>4</option>
              <option>5</option>
            </select>
        </td>
        
        <td width="3%">
          <input type="text" id="total1" name="total1" value="0" readonly="readonly" />
        </td>
      </tr>
    
      <tr>
        <td><b>Pints</b></td>
        <td>
          <form>
            <select id="Pints" onchange="updateOrder2();">
              <option>Select</option>
              <option>1</option>
              <option>2</option>
              <option>3</option>
              <option>4</option>
              <option>5</option>
            </select>
        </td>
        <td>
          <input type="text" id="total2" name="total2" value="0" readonly="readonly" />
        </td>
      </tr>
    
      <tr>
        <td></td>
        <td>
          Total
          </div>
        </td>
        <td id="orderTotal"></td>
      </tr>
    </table>
    Login or Signup to reply.
  2. Here’s one approach. It’s best to reuse functions and pass in the value that changes rather than having separate functions for each case. You can update adjacent elements based on the event target’s position in the document rather than by ID.

    Note that I’ve wrapped a single form around the entire table instead of having separate forms. Technically you don’t even need a form since you’re not submitting it anywhere.

    function updateOrder(event, price) {
      const selectedVal = event.currentTarget.value;
      let rowCost = (selectedVal * price).toFixed(2);
      const row = event.target.closest('tr');
      const input = row.querySelector('td:last-child input');
      
      // deal with deselection
      if (rowCost === 'NaN') rowCost = 0;
    
      // use a data attribute to store the numeric row total for later use
      input.setAttribute('data-val', rowCost);
      input.value = "$" + rowCost;
    
      updateTotal();
    }
    
    function updateTotal() {
      const rowTotalEls = document.querySelectorAll('#priceTable td:last-child input');
      let grandTotal = 0;
    
      rowTotalEls.forEach(function(el) {
        const rowCost = el.getAttribute('data-val');
    
        if (rowCost) {
          grandTotal += parseFloat(rowCost);
        }
      });
    
      if (grandTotal > 0) {
        document.querySelector('#total').textContent = '$' + grandTotal.toFixed(2);
      }
    }
    <form>
      <table id="priceTable" style="border: 1px solid;">
        <tr>
          <td><b>Quarts</b></td>
          <td>
            <select id="Quarts" onchange="updateOrder(event, 13);">
              <option>Select</option>
              <option>1</option>
              <option>2</option>
              <option>3</option>
              <option>4</option>
              <option>5</option>
            </select>
          </td>
    
          <td width="3%">
            <input type="text" id="total1" name="total1" value="0" readonly="readonly" />
          </td>
        </tr>
    
        <tr>
          <td><b>Pints</b></td>
          <td>
            <select id="Pints" onchange="updateOrder(event, 8);">
              <option>Select</option>
              <option>1</option>
              <option>2</option>
              <option>3</option>
              <option>4</option>
              <option>5</option>
            </select>
          </td>
          <td>
            <input type="text" id="total2" name="total2" value="0" readonly="readonly" />
          </td>
        </tr>
    
        <tr>
          <td></td>
          <td>
            Total
          </td>
          <td id="total"></td>
        </tr>
      </table>
    </form>
    Login or Signup to reply.
    • Your HTML is malformed on <form> the bees died
    • Use events in the code not in the HTML
    • Using tables for layout just makes things ‘harder’ to style so I used a set of grids in grids
    • Added the grand total update as a function
    • Put the amounts for each in a data attribute so we don’t need global variables and can still update
    • Put some ugly borders around stuff just to show what is where
    • Used * 1 various places to avoid parsing numbers
    • Moved all the style to CSS where it is easier to maintain
    • Changed names to better reflect use etc.
    function updateGrandTotal() {
      const ptotal = document.getElementById("pint-total");
      const pAmount = ptotal.dataset.currentamount * 1;
      const qtotal = document.getElementById("quart-total");
      const qAmount = qtotal.dataset.currentamount * 1;
    
      const formattedTotal = '$' + ((pAmount + qAmount).toFixed(2));
      console.log(pAmount, qAmount, formattedTotal);
      document.querySelector('.grand-total-container').textContent = formattedTotal;
    }
    
    function handleQuartsChange(event) {
      const unitPerQuart = 13;
      const quartCount = event.currentTarget.value * 1;
      const amount = quartCount * unitPerQuart;
      const total = document.getElementById("quart-total");
      total.dataset.currentamount = amount;
      total.textContent = "$" + amount.toFixed(2);
      updateGrandTotal();
    }
    
    function handlePintsChange(event) {
      const unitPerPint = 8;
      const pintCount = event.currentTarget.value * 1;
      const amount = pintCount * unitPerPint;
      const total = document.getElementById("pint-total");
      total.dataset.currentamount = amount;
      total.textContent = "$" + amount.toFixed(2);
      updateGrandTotal()
    }
    
    let quarts = document.querySelector('#quarts');
    quarts.addEventListener('change', handleQuartsChange);
    let pints = document.querySelector('#pints');
    pints.addEventListener('change', handlePintsChange);
    body,
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
      font-size: 16px;
    }
    
    body {
      // super center on the page body
      display: grid;
      place-items: center;
      grid-gap: 1em;
    }
    
    .form-container {
      border: 1px solid black;
      // super center on the container
      display: grid;
      place-items: center;
      grid-gap: 1em;
    }
    
    .block-container {
      display: grid;
      grid-template-rows: auto 1fr;
      grid-gap: 1em;
      border: solid 1px blue;
      place-items: center;
    }
    
    .header-item {
      font-weight: bold;
    }
    
    .total-container {
      padding: 0.5em;
      border: solid yellow 2px;
    }
    <div class="form-container">
      <div class="block-container">
        <label class="header-item">Quarts</label>
        <select id="quarts">
          <option>Select Quarts</option>
          <option>1</option>
          <option>2</option>
          <option>3</option>
          <option>4</option>
          <option>5</option>
        </select>
        <div class="total-container">
          <div id="quart-total" data-currentamount="0">0</div>
        </div>
      </div>
      <div class="block-container">
        <label class="header-item">Pints</label>
        <select id="pints">
          <option>Select Pints</option>
          <option>1</option>
          <option>2</option>
          <option>3</option>
          <option>4</option>
          <option>5</option>
        </select>
        <div class="total-container">
          <div id="pint-total" data-currentamount="0">0</div>
        </div>
      </div>
      <div class="block-container total-container">
        <div>Grand Total</div>
        <div class="grand-total-container">$0</div>
      </div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search