Search code examples
javascriptarraysgetelementbyid

JavaScript text box addition


I am working on a form to create an invoice. so basically, i have a button to create a table row where I can enter the code, name of product, notes, qty, price and discount. then automatically add the total price, by multiply the qty and subtracting the discount.

The problem I am having is to get the row index where the addition need to be worked. The first row it works but the second, third, etc... doesn't work.

I am asking here maybe there is some one that can find the problem. I am a beginner when it comes to javascript and basically learning while working on it, so any help it is really appreciated.

// Item Counter
var ic = 1;

// Remove an entry 
function RemoveEntryFromList(entry) {
  document.getElementById(entry).remove();
}

// Adds an entry into the "Added Items" list
function addEntryToList(p_code, p_name, p_sn, p_qty, p_price, p_discount, p_url, p_costPrice, p_qtyAvailable) {
  var entry = document.createElement("tr");
  entry.id = ("item-" + String(ic));
  document.getElementById("list-table").tBodies[0].appendChild(entry);
  p_price1 = parseFloat(p_price).toFixed(2);
  p_costPrice1 = parseFloat(p_costPrice).toFixed(2);

  entry.innerHTML = `<td><input value="${p_code}" /></td>
                                    <td><input value="${p_name}" /></td>
                                    <td><input value="${p_sn}" /></td>
                                    <td><input type="text" id="qty" value="${p_qty}" oninput="calculate()" /></td>
                                    <td><input type="text" id="price" step="0.01" min="0.00" value="${p_price1}" oninput="calculate()" /></td>
                                    <td><input type="text" id="discount" value="${p_discount}" oninput="calculate()" /></td>
                                    <td><input type="number" id="net_price" readonly /></td>
                                    <td style="text-align: center;"><button onclick="RemoveEntryFromList('${entry.id}')">&nbsp;X&nbsp;</button></td>
                                    <td style="text-align: center; cursor: pointer;"><i class="fas fa-ellipsis-v"></i></td>`;
  ic++;
}

function calculate() {
  var calc_qty = document.getElementById('qty').value;
  var calc_price = document.getElementById('price').value;
  var discount = document.getElementById('discount').value;
  var result = document.getElementById('net_price');
  var calc_discount = calc_price * (discount / 100);
  var calc_result = (calc_price - calc_discount) * calc_qty;
  result.value = calc_result;
}
<div id="container">
  <div id="list-sect">
    <button id="add-custom-item-btn" onClick="addEntryToList('', '', '', '1', '0.00', '0');" style="height: 30px;">
                <i class="fas fa-box-open"></i> Add New Entry
            </button>
  </div>

  <table id="list-table">
    <tr class="list-entry" style="height: 21px;">
      <th width="80px">Code</th>
      <th>Name</th>
      <th>notes</th>
      <th width="60px">Qty</th>
      <th width="76px">Price</th>
      <th width="65px">Disc.(%)</th>
      <th width="76px">Total Price</th>
      <th colspan="2">Remove</th>
    </tr>
  </table>
</div>


Solution

  • Don't use id's in your generated code, id's have to be unique. I changed them to classes. I also changed the calculate function so the target element is given as a parameter. In the calculate function the correct elements are found based on the element in the parameter.

    But it's a pretty ugly way of handling this. I recommend rewrite it so you do event delegation on your table like in the function below. If you don't want that then see the bottom snippet.

    //Event delgation from the table as replacement of the calculate function
    document.querySelector('#list-table').addEventListener('input', function(e) {
      //Element that triggered
      let target = e.target;
      //check if the target has the class of one of our input elements that we want to use for (re)calculation
      if (target.classList.contains('qty') ||
        target.classList.contains('price') ||
        target.classList.contains('discount') ||
        target.classList.contains('net_price')
      ) {
        //(re)calculate
        var targetRow = target.parentElement.parentElement;
        
        var calc_qty = targetRow.querySelector('.qty').value;
        var calc_price = targetRow.querySelector('.price').value;
        var discount = targetRow.querySelector('.discount').value;
        var result = targetRow.querySelector('.net_price');
        var calc_discount = calc_price * (discount / 100);
        var calc_result = (calc_price - calc_discount) * calc_qty;
        result.value = calc_result;
      }
    });
    
    // Item Counter
    var ic = 1;
    
    // Remove an entry 
    function RemoveEntryFromList(entry) {
      document.getElementById(entry).remove();
    }
    
    // Adds an entry into the "Added Items" list
    function addEntryToList(p_code, p_name, p_sn, p_qty, p_price, p_discount, p_url, p_costPrice, p_qtyAvailable) {
      var entry = document.createElement("tr");
      entry.id = ("item-" + String(ic));
      document.getElementById("list-table").tBodies[0].appendChild(entry);
      p_price1 = parseFloat(p_price).toFixed(2);
      p_costPrice1 = parseFloat(p_costPrice).toFixed(2);
    
      entry.innerHTML = `<td><input value="${p_code}" /></td>
                                        <td><input value="${p_name}" /></td>
                                        <td><input value="${p_sn}" /></td>
                                        <td><input type="text" class="qty" value="${p_qty}" /></td>
                                        <td><input type="text" class="price" step="0.01" min="0.00" value="${p_price1}" /></td>
                                        <td><input type="text" class="discount" value="${p_discount}" /></td>
                                        <td><input type="number" class="net_price" readonly /></td>
                                        <td style="text-align: center;"><button onclick="RemoveEntryFromList('${entry.id}')">&nbsp;X&nbsp;</button></td>
                                        <td style="text-align: center; cursor: pointer;"><i class="fas fa-ellipsis-v"></i></td>`;
      ic++;
    }
    <div id="container">
      <div id="list-sect">
        <button id="add-custom-item-btn" onClick="addEntryToList('', '', '', '1', '0.00', '0');" style="height: 30px;">
                    <i class="fas fa-box-open"></i> Add New Entry
                </button>
      </div>
    
      <table id="list-table">
        <tr class="list-entry" style="height: 21px;">
          <th width="80px">Code</th>
          <th>Name</th>
          <th>notes</th>
          <th width="60px">Qty</th>
          <th width="76px">Price</th>
          <th width="65px">Disc.(%)</th>
          <th width="76px">Total Price</th>
          <th colspan="2">Remove</th>
        </tr>
      </table>
    </div>

    Original answer:

    // Item Counter
    var ic = 1;
    
    // Remove an entry 
    function RemoveEntryFromList(entry) {
      document.getElementById(entry).remove();
    }
    
    // Adds an entry into the "Added Items" list
    function addEntryToList(p_code, p_name, p_sn, p_qty, p_price, p_discount, p_url, p_costPrice, p_qtyAvailable) {
      var entry = document.createElement("tr");
      entry.id = ("item-" + String(ic));
      document.getElementById("list-table").tBodies[0].appendChild(entry);
      p_price1 = parseFloat(p_price).toFixed(2);
      p_costPrice1 = parseFloat(p_costPrice).toFixed(2);
    
      entry.innerHTML = `<td><input value="${p_code}" /></td>
                                        <td><input value="${p_name}" /></td>
                                        <td><input value="${p_sn}" /></td>
                                        <td><input type="text" class="qty" value="${p_qty}" oninput="calculate(this)" /></td>
                                        <td><input type="text" class="price" step="0.01" min="0.00" value="${p_price1}" oninput="calculate(this)" /></td>
                                        <td><input type="text" class="discount" value="${p_discount}" oninput="calculate(this)" /></td>
                                        <td><input type="number" class="net_price" readonly /></td>
                                        <td style="text-align: center;"><button onclick="RemoveEntryFromList('${entry.id}')">&nbsp;X&nbsp;</button></td>
                                        <td style="text-align: center; cursor: pointer;"><i class="fas fa-ellipsis-v"></i></td>`;
      ic++;
    }
    
    function calculate(element) {
      var calc_qty = element.parentElement.parentElement.querySelector('.qty').value;
      var calc_price = element.parentElement.parentElement.querySelector('.price').value;
      var discount = element.parentElement.parentElement.querySelector('.discount').value;
      var result = element.parentElement.parentElement.querySelector('.net_price');
      var calc_discount = calc_price * (discount / 100);
      var calc_result = (calc_price - calc_discount) * calc_qty;
      result.value = calc_result;
    }
    <div id="container">
      <div id="list-sect">
        <button id="add-custom-item-btn" onClick="addEntryToList('', '', '', '1', '0.00', '0');" style="height: 30px;">
                    <i class="fas fa-box-open"></i> Add New Entry
                </button>
      </div>
    
      <table id="list-table">
        <tr class="list-entry" style="height: 21px;">
          <th width="80px">Code</th>
          <th>Name</th>
          <th>notes</th>
          <th width="60px">Qty</th>
          <th width="76px">Price</th>
          <th width="65px">Disc.(%)</th>
          <th width="76px">Total Price</th>
          <th colspan="2">Remove</th>
        </tr>
      </table>
    </div>