BobbyJones BobbyJones - 5 months ago 10
HTML Question

Javascript - Add new row to an HTML table that sums columns

With JavaScript, how can I add a new row to an HTML table that sums the values following the 2nd row.

Here's an example of what the above depicts:

enter image description here

Expected outcome:

enter image description here

Here is the html markup:

<!DOCTYPE html>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

</head>

<body>
<!DOCTYPE html>
<html>
<body>

<table border="1" style="width:100%">
<tr>
<td>Branch</td>
<td>Division</td>
<td>TallyA</td>
<td>TallyB</td>
<td>TallyC</td>
</tr>
<tr>
<td>Alpha</td>
<td>A101</td>
<td>6</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>Bravo</td>
<td>B102</td>
<td>16</td>
<td>8</td>
<td>10</td>
</tr>
<tr>
<td>Charlie</td>
<td>C103</td>
<td>11</td>
<td>17</td>
<td>21</td>
</tr>
</table>


</body>

</html>
</body>

</html>

Answer

Here is my solution. It may look verbose, but that's necessary with the complexity of this task.

First, I referenced the button and table elements. To prevent repeated clicks that will add more rows, and destroy the code, I created a boolean variable that checks whether the rows have already been summed. The code only runs the first time inside the if(!summedItems) conditional.

I then created new td elements for all five columns in the table and created text nodes for all but the division one.

I then created selectors and this is where it got tricky. The first row does not contain numerical value, so I had to query all rows from the second further. I did that with tr:nth-child(n+2).

I then need to find the third cell in each of these rows. The descendant or child selectors can be used for this. The full selector is tr:nth-child(n+2) td:nth-child(3). Repeat that for the next two, only increment the values inside td:nth-child.

Since we need to iterate through all these values, I created three separate arrays to store the values inside the third, fourth and fifth columns respectively. It's important to note that these values are of type string and they need to be converted to integers. To do that simply add a + sign before the string. Iterating over the number of elements in each query, I populated the arrays.

Now we need to add up all of these items, and we can do that with the reduce method.

Now add the textnodes to the cells, the cells to the row and finally the row to the table. Finally, set the summedItems variable to true to prevent crazy behavior.

var button = document.getElementById("total-items");
var table = document.getElementById("my-table");

var summedItems = false;

function sumItems() {
    if (!summedItems) {
        var row = document.createElement("tr");
        var branch = document.createElement("td");
        var division = document.createElement("td");
        var tallyA = document.createElement("td");
        var tallyB = document.createElement("td");
        var tallyC = document.createElement("td");
        var branchText = document.createTextNode("Total");

  
        var sumA = document.querySelectorAll("tr:nth-child(n+2) td:nth-child(3)");
        var sumB = document.querySelectorAll("tr:nth-child(n+2) td:nth-child(4)");
        var sumC = document.querySelectorAll("tr:nth-child(n+2) td:nth-child(5)");
  
        var aSums = [], bSums = [], cSums = [];
    
        for (var i = 0; i < sumA.length; i++) {
            aSums.push(+(sumA[i].innerHTML));
        }
  
        for (var i = 0; i < sumB.length; i++) {
            bSums.push(+(sumB[i].innerHTML));
        }
  
        for (var i = 0; i < sumC.length; i++) {
            cSums.push(+(sumC[i].innerHTML));
        }
  
        aSums = aSums.reduce((a,b) => a + b)     
        bSums = bSums.reduce((a,b) => a + b)
        cSums = cSums.reduce((a,b) => a + b)
  
        var tallyAText = document.createTextNode(aSums);
        var tallyBText = document.createTextNode(bSums);
        var tallyCText = document.createTextNode(cSums);
  
        branch.appendChild(branchText);

        tallyA.appendChild(tallyAText);
        tallyB.appendChild(tallyBText);
        tallyC.appendChild(tallyCText);
        
      [branch, division, tallyA, tallyB, tallyC].forEach((e) => row.appendChild(e)
        )

        table.appendChild(row);
        summedItems = true;
    }
}

button.addEventListener("click", function() {
    sumItems();
});
<table id="my-table" border="1" style="width:100%">
  <tr>
    <td>Branch</td>
    <td>Division</td>
    <td>TallyA</td>
    <td>TallyB</td>
    <td>TallyC</td>
  </tr>
  <tr>
    <td>Alpha</td>
    <td>A101</td>
    <td>6</td>
    <td>4</td>
    <td>5</td>
  </tr>
  <tr>
    <td>Bravo</td>
    <td>B102</td>
    <td>16</td>
    <td>8</td>
    <td>10</td>
  </tr>
  <tr>
    <td>Charlie</td>
    <td>C103</td>
    <td>11</td>
    <td>17</td>
    <td>21</td>
  </tr>
</table>

<button id="total-items">Total Items</button>

Comments