0

I'm very new to JS and I'm trying to learn for loops and in this case, I want to turn this into a for loop if possible. I want to calculate a static number string in cell 3, times the input number in cell 4, and output the result to a new cell 5 that has been created in the loop. Any help is much appreciated

var table = document.getElementById("table");

var Row1 = table.rows[1],
    cell1 = Row1.insertCell(5);
var Row2 = table.rows[2],
    cell2 = Row2.insertCell(5);
var Row3 = table.rows[3],
    cell3 = Row3.insertCell(5);
var Row4 = table.rows[4],
    cell4 = Row4.insertCell(5);
var Row5 = table.rows[5],
    cell5 = Row5.insertCell(5);
var Row6 = table.rows[6],
    cell6 = Row6.insertCell(5);

var x1 = table.rows[1].cells[4].getElementsByTagName('input')[0].value;
var y1 = table.rows[1].cells[3].innerHTML;
    cell1.innerHTML = y1 * x1;
var x2 = table.rows[2].cells[4].getElementsByTagName('input')[0].value;
var y2 = table.rows[2].cells[3].innerHTML;
    cell2.innerHTML = y2 * x2;
var x3 = table.rows[3].cells[4].getElementsByTagName('input')[0].value;
var y3 = table.rows[3].cells[3].innerHTML;
    cell3.innerHTML = y3 * x3;
var x4 = table.rows[4].cells[4].getElementsByTagName('input')[0].value;
var y4 = table.rows[4].cells[3].innerHTML;
    cell4.innerHTML = y4 * x4;
var x5 = table.rows[5].cells[4].getElementsByTagName('input')[0].value;
var y5 = table.rows[5].cells[3].innerHTML;
    cell5.innerHTML = y5 * x5;
var x6 = table.rows[6].cells[4].getElementsByTagName('input')[0].value;
var y6 = table.rows[6].cells[3].innerHTML;
    cell6.innerHTML = y6 * x6;
Pfft
  • 1
  • 2
  • This confuses me a bit, sorry :p Do you have any accompanying HTML? Might help to see what we're working with. – Nathan Nov 15 '20 at 14:25
  • Newest edit removed the earlier added HTML, look into the revisions for clarity. The OP seems to have copy-pasted his newest JS-code over all the previous code (including the HTML), without re-adding the newest HTML-code, without checking what he is actually overriding. Quite questionable move, in my opinion. – Oskar Grosser Nov 15 '20 at 17:32

3 Answers3

0

You can use for-loops like the one given below. Looks like you are operating on numbers, so I have added a + in front of x1's and y1's assignment to implicitly type-cast them to numbers.

for(var i = 1; i <= 6; i++) {
  var firstRow = table.rows[i], cell = firstRow.insertCell(5);
  var x1 = +table.rows[i].cells[4].getElementsByTagName('input')[0].value;
  var y1 = +table.rows[i].cells[3].innerHTML;
  cell.innerHTML = y1 * x1;
}
F. Müller
  • 3,969
  • 8
  • 38
  • 49
Saravanan
  • 7,637
  • 5
  • 41
  • 72
0

These don't need to be in functions but just to make it easier to read

function createCells() {
  cells = []
  for (let i = 1; i < 7; i++) {
    var cells[i] = table.rows[i].insertCell(5)
  }
}

function calculate() {
  for
  let (i = 1; i < 7; i++) {
    var x = table.rows[i].cells[4].getElementsByTagName('input')[0].value;
    var y = table.rows[i].cells[3].innerHTML;
    cells[i].innerHTML = (y * x);
  }
}
Coupe
  • 372
  • 2
  • 12
0

A short answer using a simple for-loop is this:

  1. Loop through every row
  2. For each row, multiply quantity with price
  3. Output total in same row

Since we basically always want to have a "total"-field in every row, we can add it in the HTML directly.
And since we know the position of the price-element and quantity-element, we can access them using fixed values as indices.

var rows = document.querySelectorAll("#pricetable tbody tr");
for (var i = 0; i < rows.length; ++i) {
  var price = rows[i].children[3].innerHTML;
  var quantity = rows[i].children[4].children[0].value;
  var total = price * quantity; // Implicit type-casting to numbers
  rows[i].children[5].innerHTML = total;
}
<table id="pricetable">
  <thead>
    <tr>
      <th>Number</th>
      <th>Product</th>
      <th>Brand</th>
      <th>Price</th>
      <th>Quantity</th>
      <th>Total</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>23456789</td>
      <td>Phone</td>
      <td>Apple</td>
      <td>6500</td>
      <td>
        <input type="text" size="3" value="1" />
      </td>
      <td></td>
    </tr>
    <tr>
      <td>22256289</td>
      <td>Phone</td>
      <td>Samsung</td>
      <td>6200</td>
      <td>
        <input type="text" size="3" value="1" />
      </td>
      <td></td>
    </tr>
    <tr>
      <td>24444343</td>
      <td>Phone</td>
      <td>Huawei</td>
      <td>4200</td>
      <td>
        <input type="text" size="3" value="1" />
      </td>
      <td></td>
    </tr>
    <tr>
      <td>19856639</td>
      <td>Tablet</td>
      <td>Apple</td>
      <td>4000</td>
      <td>
        <input type="text" size="3" value="1" />
      </td>
      <td></td>
    </tr>
    <tr>
      <td>39856639</td>
      <td>Tablet</td>
      <td>Samsung</td>
      <td>2800</td>
      <td>
        <input type="text" size="3" value="1" />
      </td>
      <td></td>
    </tr>
    <tr>
      <td>12349862</td>
      <td>Tablet</td>
      <td>Huawei</td>
      <td>3500</td>
      <td>
        <input type="text" size="3" value="1" />
      </td>
      <td></td>
    </tr>
  </tbody>
</table>

Note: When changing the position of those elements (e.g. by add a new column infront of them), their index would shift. That would make you have to update the indices in the JS-file manually.
You can make this easier for yourself by using this simple "trick":
Add specific classes to the elements (e.g. .price, .quantity, .total), allowing you to easily find them using Element.querySelector().

Note: The script only runs once, the first time the page is loaded. That means, inputting a different quantity won't update the "total"-field. For that, we need an EventListener.

Another approach
By observing the for-loop, we can see:

  • We access only one row for each iteration
  • The order in which we access each row is irrelevant

Since both these points are checked, we can use a for...of-loop (also called foreach-loop or enhanced for-loop). A for...of-loop is (in my opinion) easier to read, and tells what we checked using the list above by itself.
Note: Be wary of the difference of the for...of-loop and the for...in-loop.

Now, we could calculate the total right then and there in the loop, but thinking ahead, we want to perform the same calculation again when inputting a new quantity-value. We can reduce the duplicate code by making the calculation a Function updateRowTotal(), making the code easier to debug and understand.

To actually update the total when entering a new quantity-value, we can use an EventListener that calls a function automatically when a new value is entered into the <input>-field (by calling updateRowTotal(evt.target.closest("tr"))).

function clamp(min, value, max) {
  return Math.max(min, Math.min(value, max));
}

for (let row of document.querySelectorAll("#pricetable tbody tr")) {
  updateRowTotal(row);
  row.querySelector("input.quantity").addEventListener("input", evt => {
    // Add '/*' before this comment to "remove" this extra part
    // The 5 lines below are to clamp 'value' between 'min' and 'max'
    let min = parseInt(evt.target.getAttribute("min"));
    let max = parseInt(evt.target.getAttribute("max"));
    if (isNaN(min)) min = Number.MIN_SAFE_INTEGER;
    if (isNaN(max)) max = Number.MAX_SAFE_INTEGER;
    evt.target.value = clamp(min, evt.target.value, max);
    // */
    updateRowTotal(evt.target.closest("tr"));
  });
}

function updateRowTotal(row) {
  row.querySelector(".total").innerHTML = row.querySelector(".price").innerHTML * row.querySelector(".quantity").value;
}
<table id="pricetable">
  <thead>
    <tr>
      <th>Price</th>
      <th>Quantity</th>
      <th>Row-Total</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td class="price">6500</td>
      <td>
        <input class="quantity" type="number" min="0" max="999" value="1" />
      </td>
      <td class="total"></td>
    </tr>
    <tr>
      <td class="price">6200</td>
      <td>
        <input class="quantity" type="number" min="0" max="999" value="1" />
      </td>
      <td class="total"></td>
    </tr>
    <tr>
      <td class="price">4200</td>
      <td>
        <input class="quantity" type="number" min="0" max="999" value="1" />
      </td>
      <td class="total"></td>
    </tr>
    <tr>
      <td class="price">4000</td>
      <td>
        <input class="quantity" type="number" min="0" max="999" value="1" />
      </td>
      <td class="total"></td>
    </tr>
    <tr>
      <td class="price">2800</td>
      <td>
        <input class="quantity" type="number" min="0" max="999" value="1" />
      </td>
      <td class="total"></td>
    </tr>
    <tr>
      <td class="price">3500</td>
      <td>
        <input class="quantity" type="number" min="0" max="999" value="1" />
      </td>
      <td class="total"></td>
    </tr>
  </tbody>
</table>

Sidenote
Making the <input>-field of type="number" prevents any non-numeric character to be entered.
And since the min- and max-attributes only prevent form-submission, we have to code the value-clamping ourselves. This is easily done by reading the values of the attributes and clamping the value to their defined range. Note that we have added default values for both min and max, being the lower-most and upper-most safe integer-value.

Oskar Grosser
  • 2,804
  • 1
  • 7
  • 18