user3344186
user3344186

Reputation: 191

Bug in the calculation of total in a dynamic table

I designed a table where you can add dynamic rows, the user can select a quantity and a price for each of them. I have a series of very simple functions that allow me to delete, empty the entire table or calculate the total of all products plugged.

So far everything works fine, the problem occurs when I create 3 rows, I add it to each of their values​​, then I decided to delete the second row and calculate the total. As you can see, the calculation is flawed, in fact I only returns the total of the first product added to the table. I can not understand why the script does not work properly. Can anyone help me solve this problem?

<html>
<table style='width:100%' id='table'>
   <tr>
       <td colspan='3'><input type="button" style="background-color:#00FA9A" value="add product" onclick="add()" id="button"><input type="button" style="background-color:red" value="Delete all" onclick="deleteall()" id="button">
       </td>
   </tr>
   <tr>
       <td>Quantity</td>
       <td>€</td>
       <td>Delete</td>
    </tr>
 </table>
 <input type="button" id="button" value="Calc total" onclick="total()"><input type="text" class='input' id="total">€
 </html>

<script>

var idx = 0;        
var cont = 0;       
var buttcont = 0;   
var quantity, priece;


function deleteall()
{
    location.reload();
}


function add()
{

    var tableRef = document.getElementById('table').getElementsByTagName('tbody')[0];

    var newRow   = tableRef.insertRow(tableRef.rows.length);
    newRow.id = "row" + cont; 
    cont++;

    var newCell1  = newRow.insertCell(0);
    var newCell2 = newRow.insertCell(1);
    var newCell3 = newRow.insertCell(2);
    var input1 = document.createElement('input'),
        input2 = document.createElement('input');
        input3 = document.createElement('button');

    input1.type = 'number';
    input1.style.width = "100%";
    input1.id = "priece" + idx;
    input1.min = 0;
    input1.value = 1;

    input2.type = 'text';
    input2.min = 1;
    input2.style.width = "100%";
    input2.id = "quantity" + idx;

    input3.class = 'button';
    input3.innerHTML = "Delete";

    if(input3.attachEvent) input3. attachEvent('onclick',function(e){deleted(e);})
    else if(input3.addEventListener) input3.addEventListener('click',function(e){deleted(e);},false)

    newCell1.appendChild(input1);
    newCell2.appendChild(input2);
    newCell3.appendChild(input3);

    idx++;
} 

function deleted(e)
{
    if(document.removeChild && document.getElementById && document.getElementsByTagName)
    {
        if(!e) e = window.event;
        var srg = (e.target)?e.target:e.srcElement;

        while(srg.tagName != "TR"){srg = (srg.parentNode)?srg.parentNode:srg.parentElement}

        var tb = document.getElementById('table').getElementsByTagName('TBODY')[0];

        tb.removeChild(srg);
        cont--;
        idx--;
    }
}

function total()
{
    var total = 0;

    for(var i = 0; i < idx; i++)
    {
        quantity = document.getElementById('quantity' + i).value;
        priece = document.getElementById('priece' + i).value; 
        total += quantity * priece;
        document.getElementById('total').value = total;
    }
}

Upvotes: 0

Views: 212

Answers (1)

Yury Tarabanko
Yury Tarabanko

Reputation: 45106

The problem comes from the fact that when you delete a row inside a table (not the last one) you have a gap in ids. getElementById will return null and your total function will raise an exception.

  • Add 3 products: idx is 3, ids in the DOM are 0, 1, 2;
  • Remove product 1: idx is 2, ids in the DOM are 0, 2; => total will throw for i == 1

Actually you can avoid looping through ids by assigning a class to your inputs. Demo.

function total()
{
    var total = 0,
        prices = document.querySelectorAll('.price'),
        quantities = document.querySelectorAll('.quantity'), 
        i = 0, len = prices.length;

    for(; i < len; i++) {
        total += prices[i].value*quantities[i].value;    
    }

    document.getElementById('total').value = total;
}

Upvotes: 1

Related Questions