The value of total price changes on the first row only

When I entered the unit price* quantity, it works and the values for total price changes on the 1st row only. However, it could not be done on the rest of the rows. So, do u mind helping me to figure out and help me solve my problem. Below are the codes I’m working on right now:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="styles.css">
        <title>Book Ordering System</title>
    <style>
     .top-bottom{
         background-color: skyblue;
     }
     .total_column{
         background-color: silver;
     }
     .all:hover{
         background-color: yellow;
     }
     td .align-right input {
   text-align: right;
}
    </style>
    </head>
    <body>
        <h1>Book Ordering System</h1>
        <table border="2" onchange="calculateTotal()">
            <form method="post">
            <tr style="font-weight:bold" ; class="top-bottom all" >
                <td>No.</td>
                <td>Book Title</td>
                <td>Author</td>
                <td>Category</td>
                <td style="text-align: right;">Unit Price</td>
                <td style="text-align: right;">Quantity</td>
                <td style="text-align: right;">Total</td>
            </tr>
            <tr class="all">
            <td>1</td>
            <td>
                <label for="sec1"></label>
              <input type="text" name="sec1" id="sec1" value=""/>
            </td>
            <td>
                <label for="sec2"></label>
                <input type="text" name="sec2" id="sec2" value=""/>
            </td>
            <td>
                <select name="category" id="category">
                <option value="choose">Please choose the category...</option>
                <option value="biz">Business</option>
                <option value="fiction">Fiction</option>
                <option value="maths">Mathematics</option>
                <option value="tech">Technology</option>
                </select>
            </td> 
            <td>
                <div class="align-right">
                <label for="sec3"></label>
                <input type="text" name="sec3" id="sec3" value="0.00"   />
                </div>
            </td>
            <td>
                <div class="align-right">
                <label for="sec4"></label>
                <input type="text" name="sec4" id="sec4" value="0"  />
                </div>
            </td>
            <td>
                <div class="align-right">
                <label for="sec5"></label>
                <input type="text" name="sec5" id="sec5" value="0.00" readonly="readonly" class="total_column"  />
                </div>
            </td>
            </tr>
            <tr class="all">
                <td>2</td>
                <td>
                    <label for="sec1"></label>
                  <input type="text" name="sec1" id="sec1" value=""/>
                </td>
                <td>
                    <label for="sec2"></label>
                    <input type="text" name="sec2" id="sec2" value=""/>
                </td>
                <td>
                    <select name="category" id="category">
                    <option value="choose">Please choose the category...</option>
                    <option value="biz">Business</option>
                    <option value="fiction">Fiction</option>
                    <option value="maths">Mathematics</option>
                    <option value="tech">Technology</option>
                    </select>
                </td> 
            
                <td>
                    <div class="align-right">
                    <label for="sec3"></label>
                    <input type="text" name="sec3" id="sec3" value="0.00"/>
                    </div>
                </td>
                <td>
                    <div class="align-right">
                    <label for="sec4"></label>
                    <input type="text" name="sec4" id="sec4" value="0"/>
                    </div>
                </td>
                <td>
                    <div class="align-right">
                    <label for="sec5"></label>
                    <input type="text" name="sec5" id="sec5" value="0.00" readonly="readonly" class="total_column " />
                    </div>
                </td>
                </tr>
                <tr class="all">
                    <td>3</td>
                <td>
                    <label for="sec1"></label>
                  <input type="text" name="sec1" id="sec1" value=""/>
                </td>
                <td>
                    <label for="sec2"></label>
                    <input type="text" name="sec2" id="sec2" value=""/>
                </td>
                <td>
                    <select name="category" id="category">
                    <option value="choose">Please choose the category...</option>
                    <option value="biz">Business</option>
                    <option value="fiction">Fiction</option>
                    <option value="maths">Mathematics</option>
                    <option value="tech">Technology</option>
                    </select>
                </td> 
                <td>
                    <div class="align-right">
                    <label for="sec3"></label>
                    <input type="text" name="sec3" id="sec3" value="0.00"/>
                    </div>
                </td>
                <td>
                    <div class="align-right">
                    <label for="sec4"></label>
                    <input type="text" name="sec4" id="sec4" value="0"/>
                    </div>
                </td>
                <td>
                    <div class="align-right">
                    <label for="sec5"></label>
                    <input type="text" name="sec5" id="sec5" value="0.00" readonly="readonly" class="total_column" />
                    </div>
                </td>
                </tr>
                <tr class="all">
                    <td>4</td>
                <td>
                    <label for="sec1"></label>
                  <input type="text" name="sec1" id="sec1" value=""/>
                </td>
                <td>
                    <label for="sec2"></label>
                    <input type="text" name="sec2" id="sec2" value=""/>
                </td>
                <td>
                    <select name="category" id="category">
                    <option value="choose">Please choose the category...</option>
                    <option value="biz">Business</option>
                    <option value="fiction">Fiction</option>
                    <option value="maths">Mathematics</option>
                    <option value="tech">Technology</option>
                    </select>
                </td> 
                <td>
                    <div class="align-right">
                    <label for="sec3"></label>
                    <input type="text" name="sec3" id="sec3" value="0.00"/>
                    </div>
                </td>
                <td>
                    <div class="align-right">
                    <label for="sec4"></label>
                    <input type="text" name="sec4" id="sec4" value="0"/>
                    </div>
                </td>
                <td>
                    <div class="align-right">
                    <label for="sec5"></label>
                    <input type="text" name="sec5" id="sec5" value="0.00" readonly="readonly" class="total_column" />
                    </div>
                </td>
                </tr>
                <tr class="all">
                    <td>5</td>
                <td>
                    <label for="sec1"></label>
                  <input type="text" name="sec1" id="sec1" value=""/>
                </td>
                <td>
                    <label for="sec2"></label>
                    <input type="text" name="sec2" id="sec2" value=""/>
                </td>
                <td>
                    <select name="category" id="category">
                    <option value="choose">Please choose the category...</option>
                    <option value="biz">Business</option>
                    <option value="fiction">Fiction</option>
                    <option value="maths">Mathematics</option>
                    <option value="tech">Technology</option>
                    </select>
                </td> 
                <td>
                    <div class="align-right">
                    <label for="sec3"></label>
                    <input type="text" name="sec3" id="sec3" value="0.00"/>
                    </div>
                </td>
                <td>
                    <div class="align-right">
                    <label for="sec4"></label>
                    <input type="text" name="sec4" id="sec4" value="0"/>
                    </div>
                </td>
                <td>
                    <div class="align-right">
                    <label for="sec5"></label>
                    <input type="text" name="sec5" id="sec5" value="0.00"   readonly="readonly"  class="total_column"/>
                    </div>
                </td>
                </tr>
                <tr class="top-bottom all">
                    <td colspan="5" align="right">
                     <div class="align-right" >
                     <input type="button" onclick="calculateTotal()" value="Calculate Grand Total Price">
                     </div>
                    </td>
                    <td colspan="2" align="right">
                    <div class="align-right">
                    <input type="text" name="sec6" id="sec6" value="0.00" readonly="readonly" style="background-color: silver; font-size: 18pt;"/>
                    </div>
                    </td>
                </tr>
            </form>
        </table>
        
    </body>
    <script>
    
    function calculateTotal(){   
         // Get the input values //            
    a = Number(document.getElementById("sec3").value);  
    b = Number(document.getElementById("sec4").value);     

    // Do the multiplication
    c = a*b;                                          

    // Set the value of the total
    document.getElementById("sec5").value = c;  
    }
    
    </script>
</html>

JS is not my thing but I can give you some hints (as I assume this is some sort of lesson/test) to point you in the right direction.

In your code above you have copied the first row 5 times along with all the name and id attributes. IDs in html must be unique so you cannot have more than one. You need to change all the ids (and for and name attributes) in the extra rows and make them all unique.

e.g. For example in the second row you’d do something like this:

 <label for="row2sec1"></label>
          <input type="text" name="row2sec1" id="row2sec1" value="" />

Which for the whole row would look like this.

    <tr class="all">
        <td>2</td>
        <td>
          <label for="row2sec1"></label>
          <input type="text" name="row2sec1" id="row2sec1" value="" />
        </td>
        <td>
          <label for="row2sec2"></label>
          <input type="text" name="row2sec2" id="row2sec2" value="" />
        </td>
        <td>
          <select name="row2category" id="row2category">
            <option value="choose">Please choose the category...</option>
            <option value="biz">Business</option>
            <option value="fiction">Fiction</option>
            <option value="maths">Mathematics</option>
            <option value="tech">Technology</option>
          </select>
        </td>

        <td>
          <div class="align-right">
            <label for="row2sec3"></label>
            <input type="text" name="row2sec3" id="row2sec3" value="0.00" />
          </div>
        </td>
        <td>
          <div class="align-right">
            <label for="row2sec4"></label>
            <input type="text" name="row2sec4" id="row2sec4" value="0" />
          </div>
        </td>
        <td>
          <div class="align-right">
            <label for="row2sec5"></label>
            <input type="text" name="row2sec5" id="row2sec5" value="0.00" readonly="readonly" class="total_column " />
          </div>
        </td>
      </tr>

Then you’d need to do the same for all the other rows using unique ids each time.

In your existing JS you just add the totals in row1 because even though you have duplicated the IDs html does not allow this and the JS just finds the one element anyway in the first row anyway, (document.getElementByID only gets one element anyway).

If you were to extend the logic of your current system and use the extra row I gave above then for the first two rows the JS would be this.

  <script>
    function calculateTotal() {
      // Get the input values //            
      a = Number(document.getElementById("sec3").value);
      b = Number(document.getElementById("sec4").value);
      a2 = Number(document.getElementById("row2sec3").value);
      b2 = Number(document.getElementById("row2sec4").value);
      // Do the multiplication
      c = a * b;
      c2 = a2 * b2;
      // Set the value of the total
      document.getElementById("sec5").value = c;
      document.getElementById("row2sec5").value = c2;
    }
  </script>

Of course you need to extend that logic to all 5 rows and would mean repeating the code 5 times with new variables and ids etc. That would give you an answer in the most simplistic way but is not the way to do it in the real world as you really want a way to cater for more rows or less rows automatically.

What you really want to do is have a loop that cycles through however many rows you have in place (get js to find the number of table rows with values that need updating) and then update the values of each row accordingly using an index or some other mechanism to identify the fields that need to be updated. I’ll leave that part to the js experts here to chime in.

Note that you cannot put your form start tags and end tags where you have placed them as they are invalid in that position. They must got outside the table tag as nothing but table elements are allowed inside a table (all content in a table goes inside a td or th tag).

Lastly you have placed your script outside the body tag and that is invalid also. the script tag must go before the closing body tag. If you run your html through the w3c validator it will point out all these errors including your invalid use of multiple ids and is a great tool for beginners to use every time they write html.

2 Likes

Thanks @PaulOB for taking a look. I’m going to try and give a fresh take myself too.

Throughout the following I’ll comment out lines of code to indicate that those were the old line before it gets updated. If you choose to use sections of the code those commented lines shouldn’t remain in the code.

Styles

There is a style sheet with some other styles declared in a separate style tag. Hopefully those other styles are not a permanent fixture, and are only there to assist with this investigation.

Inline event handler

The inline event handler on the table element is a bad practice, as it’s spreading your JS code all over the place. The improved way to do that is to add an event listener at the end of the scripting code.

        <!--<table border="2" onchange="calculateTotal()">-->
        <table border="2">
...
                     <!--<input type="button" onclick="calculateTotal()" value="Calculate Grand Total Price">-->
                     <input type="button" value="Calculate Grand Total Price">
    var table = document.querySelector("table");
    table.addEventListener("change", calculateTotal);
    var button = document.querySelector("tfoot [type=button]");
    button.addEventListener("click", calculateTotal);

Form / Table interaction

Currently the form is inside of the table tag. It tends to make more sense to keep the table parts together, with the form outside of the table wrapping around everything.

        <!--<table border="2">
            <form method="post">-->
        <form method="post">-->
            <table border="2">
            <!--</form>
        </table>-->
            </table>
        </form>

Remove Inline CSS

Next up, I spot some inline CSS styles too on the TR element. Those need to be removed from the within HTML, and moved up to the style tag in the head, and preferably later on out to a css file.

    <style>
      .top-bottom {
        background-color: skyblue;
        font-weight: bold;
      }
    </style>
...
            <!--<tr style="font-weight:bold" ; class="top-bottom all" >-->
            <tr class="top-bottom all">

However, I wouldn’t use CSS to style the top and bottom rows of the table. That’s what the <th> tag is used for instead of <td>. The bold can now be removed from that top-bottom class.

     .top-bottom {
        background-color: skyblue;
        /*font-weight: bold;*/
     }
                <tr class="top-bottom all">
                    <th>No.</th>
                    <th>Book Title</th>
                    <th>Author</th>
                    <th>Category</th>
                    <th style="text-align: right;">Unit Price</th>
                    <th style="text-align: right;">Quantity</th>
                    <th style="text-align: right;">Total</th>
                </tr>

The top-bottom class can also be removed, because there are <thead> and <tfoot> sections that help you to achieve that instead in tables. When it comes to tfoot though, older browsers can’t have that after the tbody, so typically the thead and tfoot are defined first, with tbody coming afterwards. The table then reorganises them so that tfoot is shown at the bottom where you would expect it to be.

     /*.top-bottom {*/
     thead, tfoot {
        background-color: skyblue;
     }
                <thead>
                    <!--<tr class="top-bottom all">-->
                    <tr class="all">
                        <th>No.</th>
                        <th>Book Title</th>
                        <th>Author</th>
                        <th>Category</th>
                        <th>Unit Price</th>
                        <th>Quantity</th>
                        <th>Total</th>
                    </tr>
                </thead>
                <tfoot>
                    <!--<tr class="top-bottom all">-->
                    <tr class="all">
                        ...
                    </tr>
                </tfoot>
                <tbody>
                  ...
                </tbody>


Removing the all class

I see that you have an all class on every table row. That is a bad use of a class name, and should instead be done from the style declarations section instead.

    ./*all:hover {*/
    .tr:hover {
        background-color: yellow;
    }

And now, the all class can be removed from everywhere in the HTML code. For example:

                    <!--<tr class="all">-->
                    <tr>

Dealing with right-align

I see that you are also aligning the last three column to the right. That seems to be because you want to appropriately align the numbers. Instead of scattering those align parts all over the code, we should instead remove the inline CSS code from being within the HTML code and use a CSS declaration to achieve the alignment instead.

    tbody td:nth-child(5) input,
    tbody td:nth-child(6) input,
    tbody td:nth-child(7) input {
        text-align: right;
    }
                <tr>
                    <th>No.</th>
                    <th>Book Title</th>
                    <th>Author</th>
                    <th>Category</th>
                    <!--<th style="text-align: right;">Unit Price</th>-->
                    <th>Unit Price</th>
                    <!--<th style="text-align: right;">Quantity</th>-->
                    <th>Quantity</th>
                    <!--<th style="text-align: right;">Total</th>-->
                    <th>Total</th>
                </tr>

We can also do similar with the footer, making all of that right aligned without using any HTML classes to achieve that.

Remove inline CSS styles from footer

The background color and font size should be removed from the footer HTML code too, and moved to the CSS declarations section.

#sec6 {
    background-color: silver;
    font-size: 18pt;
}
    <td colspan="2">
        <!--<input type="text" name="sec6" id="sec6" value="0.00" readonly="readonly" style="background-color: silver; font-size: 18pt;"/>-->
        <input type="text" name="sec6" id="sec6" value="0.00" readonly="readonly"/>
    </td>

And now that the CSS is separate, we can more easily work on improving it. It is the input cell in the right-most cell that gets colored silver, so we can update the CSS to more clearly represent that.

td:last-of-type input {
    background-color: silver;
}
tfoot #sec6 {
    font-size: 18pt;
}

And because of that last-of-type CSS declaration, we can remove all of the total_column classes from the HTML code too.

We also don’t need that #sec6 declaration in the styles, because e can use last-of-type to help us achieve that too.

        tfoot td:last-of-type input {
            font-size: 18pt;
        }

Remove mystery div

There are also what looks to be mystery div tags, that don’t seem to achieve anything. Those can be removed too.

                        <td>
                            <!--<div>-->
                            <label for="sec3"></label>
                            <input type="text" name="sec3" id="sec3" value="3.00"   />
                            <!--</div>-->
                        </td>

Cleaning up

Lastly, it’s not valid for the JS script to be below the <body> tag. The JS script should be just above the closing body tag, instead of being below.

<!--</body>-->
    <script>
        ...
    </script>
</body>

And after running the updated code through jsbeautifier.io we have the updated code, that’s simplified and ready to have the JS code worked on.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="styles.css">
    <title>Book Ordering System</title>
    <style>
        thead,
        tfoot {
            background-color: skyblue;
        }

        tbody td:nth-child(5) input,
        tbody td:nth-child(6) input,
        tbody td:nth-child(7) input {
            text-align: right;
        }

        tr:hover {
            background-color: yellow;
        }

        td:last-of-type input {
            background-color: silver;
        }

        tfoot,
        tfoot input {
            text-align: right;
        }

        tfoot td:last-of-type input {
            font-size: 18pt;
        }
    </style>
</head>

<body>
    <h1>Book Ordering System</h1>
    <form method="post">
        <table border="2">
            <thead>
                <tr>
                    <th>No.</th>
                    <th>Book Title</th>
                    <th>Author</th>
                    <th>Category</th>
                    <th>Unit Price</th>
                    <th>Quantity</th>
                    <th>Total</th>
                </tr>
            </thead>
            <tfoot>
                <tr>
                    <td colspan="5">
                        <input type="button" value="Calculate Grand Total Price">
                    </td>
                    <td colspan="2">
                        <input type="text" name="grandTotal" id="grandTotal" value="0.00" readonly="readonly">
                    </td>
                </tr>
            </tfoot>
            <tbody>
                <tr>
                    <td>1</td>
                    <td>
                        <label for="sec1"></label>
                        <input type="text" name="sec1" id="sec1" value="" />
                    </td>
                    <td>
                        <label for="sec2"></label>
                        <input type="text" name="sec2" id="sec2" value="" />
                    </td>
                    <td>
                        <select name="category" id="category">
                            <option value="choose">Please choose the category...</option>
                            <option value="biz">Business</option>
                            <option value="fiction">Fiction</option>
                            <option value="maths">Mathematics</option>
                            <option value="tech">Technology</option>
                        </select>
                    </td>
                    <td>
                        <label for="sec3"></label>
                        <input type="text" name="sec3" id="sec3" value="0.00" />
                    </td>
                    <td>
                        <label for="sec4"></label>
                        <input type="text" name="sec4" id="sec4" value="0" />
                    </td>
                    <td>
                        <label for="sec5"></label>
                        <input type="text" name="sec5" id="sec5" value="0.00" readonly="readonly" />
                    </td>
                </tr>
                <tr>
                    <td>2</td>
                    <td>
                        <label for="sec1"></label>
                        <input type="text" name="sec1" id="sec1" value="" />
                    </td>
                    <td>
                        <label for="sec2"></label>
                        <input type="text" name="sec2" id="sec2" value="" />
                    </td>
                    <td>
                        <select name="category" id="category">
                            <option value="choose">Please choose the category...</option>
                            <option value="biz">Business</option>
                            <option value="fiction">Fiction</option>
                            <option value="maths">Mathematics</option>
                            <option value="tech">Technology</option>
                        </select>
                    </td>

                    <td>
                        <label for="sec3"></label>
                        <input type="text" name="sec3" id="sec3" value="0.00" />
                    </td>
                    <td>
                        <label for="sec4"></label>
                        <input type="text" name="sec4" id="sec4" value="0" />
                    </td>
                    <td>
                        <label for="sec5"></label>
                        <input type="text" name="sec5" id="sec5" value="0.00" readonly="readonly" />
                    </td>
                </tr>
                <tr>
                    <td>3</td>
                    <td>
                        <label for="sec1"></label>
                        <input type="text" name="sec1" id="sec1" value="" />
                    </td>
                    <td>
                        <label for="sec2"></label>
                        <input type="text" name="sec2" id="sec2" value="" />
                    </td>
                    <td>
                        <select name="category" id="category">
                            <option value="choose">Please choose the category...</option>
                            <option value="biz">Business</option>
                            <option value="fiction">Fiction</option>
                            <option value="maths">Mathematics</option>
                            <option value="tech">Technology</option>
                        </select>
                    </td>
                    <td>
                        <label for="sec3"></label>
                        <input type="text" name="sec3" id="sec3" value="0.00" />
                    </td>
                    <td>
                        <label for="sec4"></label>
                        <input type="text" name="sec4" id="sec4" value="0" />
                    </td>
                    <td>
                        <label for="sec5"></label>
                        <input type="text" name="sec5" id="sec5" value="0.00" readonly="readonly" />
                    </td>
                </tr>
                <tr>
                    <td>4</td>
                    <td>
                        <label for="sec1"></label>
                        <input type="text" name="sec1" id="sec1" value="" />
                    </td>
                    <td>
                        <label for="sec2"></label>
                        <input type="text" name="sec2" id="sec2" value="" />
                    </td>
                    <td>
                        <select name="category" id="category">
                            <option value="choose">Please choose the category...</option>
                            <option value="biz">Business</option>
                            <option value="fiction">Fiction</option>
                            <option value="maths">Mathematics</option>
                            <option value="tech">Technology</option>
                        </select>
                    </td>
                    <td>
                        <label for="sec3"></label>
                        <input type="text" name="sec3" id="sec3" value="0.00" />
                    </td>
                    <td>
                        <label for="sec4"></label>
                        <input type="text" name="sec4" id="sec4" value="0" />
                    </td>
                    <td>
                        <label for="sec5"></label>
                        <input type="text" name="sec5" id="sec5" value="0.00" readonly="readonly" />
                    </td>
                </tr>
                <tr>
                    <td>5</td>
                    <td>
                        <label for="sec1"></label>
                        <input type="text" name="sec1" id="sec1" value="" />
                    </td>
                    <td>
                        <label for="sec2"></label>
                        <input type="text" name="sec2" id="sec2" value="" />
                    </td>
                    <td>
                        <select name="category" id="category">
                            <option value="choose">Please choose the category...</option>
                            <option value="biz">Business</option>
                            <option value="fiction">Fiction</option>
                            <option value="maths">Mathematics</option>
                            <option value="tech">Technology</option>
                        </select>
                    </td>
                    <td>
                        <label for="sec3"></label>
                        <input type="text" name="sec3" id="sec3" value="0.00" />
                    </td>
                    <td>
                        <label for="sec4"></label>
                        <input type="text" name="sec4" id="sec4" value="0" />
                    </td>
                    <td>
                        <label for="sec5"></label>
                        <input type="text" name="sec5" id="sec5" value="0.00" readonly="readonly" />
                    </td>
                </tr>
            </tbody>
        </table>
    </form>
    <script>
        function calculateTotal() {
            // Get the input values //            
            a = Number(document.getElementById("sec3").value);
            b = Number(document.getElementById("sec4").value);

            // Do the multiplication
            c = a * b;

            // Set the value of the total
            document.getElementById("sec5").value = c;
        }
        var table = document.querySelector("table");
        table.addEventListener("change", calculateTotal);
        var button = document.querySelector("tfoot [type=button]");
        button.addEventListener("click", calculateTotal);
    </script>
</body>

</html>

I’m pretty sure that people in the HTML+CSS forum can apply further wisdom to those parts of your code, but that’s all from me on it for now.

Next up I’ll work on the JS code and get that working.

1 Like

The JS code is relatively simple. All it needs to do is to lop through each row of the <tbody> section, get the 5th, 6th, and 7th <td> from each row, and get the number from each input to perform the calculation.

            var table = document.querySelector("table");
            var rows = table.querySelectorAll("tbody tr");
            rows.forEach(function calcRow(row) {
                var unitsField = row.querySelector("td:nth-of-type(5) input");
                var quantityField = row.querySelector("td:nth-of-type(6) input");
                var totalField = row.querySelector("td:nth-of-type(7) input");
                var units = Number(unitsField.value);
                var quantity = Number(quantityField.value);
                totalField.value = units * quantity;
            });

For the grand total it’s just a matter of looping through the rows again, and adding up the totals.

            var grandTotal = Array.from(rows).reduce(function calcTotal(total, row) {
                var totalField = row.querySelector("td:nth-of-type(7) input");
                return total + Number(totalField.value);
            }, 0);
            var footerRow = table.querySelector("tfoot tr");
            var grandTotalField = footerRow.querySelector("td:last-of-type input");
            grandTotalField.value = grandTotal;

Here’s the full scripting code that solves all of the problems for you.

        function calculateTotal() {
            var table = document.querySelector("table");
            var rows = table.querySelectorAll("tbody tr");
            rows.forEach(function calcRow(row) {
                var unitsField = row.querySelector("td:nth-of-type(5) input");
                var quantityField = row.querySelector("td:nth-of-type(6) input");
                var totalField = row.querySelector("td:nth-of-type(7) input");
                var units = Number(unitsField.value);
                var quantity = Number(quantityField.value);
                totalField.value = units * quantity;
            });
            var grandTotal = Array.from(rows).reduce(function calcTotal(total, row) {
                var totalField = row.querySelector("td:nth-of-type(7) input");
                return total + Number(totalField.value);
            }, 0);
            var footerRow = table.querySelector("tfoot tr");
            var grandTotalField = footerRow.querySelector("td:last-of-type input");
            grandTotalField.value = grandTotal;
        }
        var table = document.querySelector("table");
        table.addEventListener("change", calculateTotal);
        var button = document.querySelector("tfoot [type=button]");
        button.addEventListener("click", calculateTotal);
1 Like

@PaulOB , @Paul_Wilkins. That helps a lot. Thank you very much effort and explanation. Really appreciate it.

1 Like

Glad to help. One other thing I noticed on looking back at the CSS code, is that the style declarations can be usefully grouped together as Fonts, Layout, and Colors.

        /* Fonts */
        tfoot td:last-of-type input {
            font-size: 18pt;
        }

        /* Layout */
        tbody td:nth-child(5) input,
        tbody td:nth-child(6) input,
        tbody td:nth-child(7) input {
            text-align: right;
        }
        tfoot,
        tfoot input {
            text-align: right;
        }
        
        /* Colors */
        thead {
            background-color: skyblue;
        }
        tr:hover {
            background-color: yellow;
        }
        td:last-of-type input {
            background-color: silver;
        }
        tfoot {
            background-color: skyblue;
        }        

This Fonts, Layout, and Colors is a good place to start, and helps you to more easily make sense of things as you’re working with the styles.

Does @paulob or others have further advice on grouping and organising together style declarations?

1 Like

Brilliant job as usual @Paul_Wilkins. I don’t have much to add as you’ve done it all :slight_smile:

Grouping selectors can be useful but I tend to like keeping all the rules for an element together in the same style block as often I don’t change just the one thing. e.g. the client says I want it red now and moved to the left with a bigger font. If you have split fonts, styles and layout you have to make changes in multiple places with more chance for error. However that’s just the way I work and I know its accepted that grouping styles should be a better approach. Now that we have css variables the issue isn’t quite the same as all the variables can be declared at the start and you can change the variables to make your colour or font changes. Therefore grouping variables may be a good approach. In the end use a systematic approach that works for you and stick to it.

As an aside these days I generally (on larger projects) avoid doing things like this:

tbody td:nth-child(5) input,
tbody td:nth-child(6) input,
tbody td:nth-child(7) input {
            text-align: right;
}

That code relies heavily on the html structure and should the project evolve over time and a client decides they want an extra cell at the beginning of the table then those rules above immediately target the wrong elements. (Not to mention the code above would affect all tables in the project should they have that number of cells).

On larger projects it is good to decouple the css from the html and I would have added a simple class on those cells in the html. We can then swap that block of rules for one simple rule.

e.g.

input.values {
            text-align: right;
}

… or even simpler depending on specificity:

.values {
            text-align: right;
}

That makes specificity easier and means that the number of cells can change and the code still works. It also makes the css easier to understand because you don’t have to count the number of cells to work out which one you are targeting.

On small projects under your own control its not an issue but if the project is likely to evolve over time or you are handing over to a client to manage then I prefer to add the extra class in the html .:slight_smile:

3 Likes

Yeah, and regarding the logic and HTML I was just going to suggest using an actual output element for the total prices; this allows directly specifying the inputs from which the result is getting calculated using the for attribute:

<form>
  <table>
    <thead>
      <tr>
        <th>Book</th>
        <th>Price</th>
        <th>Quantity</th>
        <th>Total</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>The Catcher In The Rye</td>
        <td><input type="number" value="0" step="0.1" min="0" id="price-0" name="price-0"></td>
        <td><input type="number" value="0" step="1" min="0" id="quantity-0" name="quantity-0"></td>
        <td><output for="price-0 quantity-0" name="total-0">0.00</output></td>
      </tr>
      <tr>
        <td>Dune</td>
        <td><input type="number" value="0" step="0.1" min="0" id="price-1" name="price-1"></td>
        <td><input type="number" value="0" step="1" min="0" id="quantity-1" name="quantity-1"></td>
        <td><output for="price-1 quantity-1" name="total-1">0.00</output></td>
      </tr>
      <tr>
        <td>Equal Rites</td>
        <td><input type="number" value="0" step="0.1" min="0" id="price-2" name="price-2"></td>
        <td><input type="number" value="0" step="1" min="0" id="quantity-2" name="quantity-2"></td>
        <td><output for="price-2 quantity-2" name="total-2">0.00</output></td>
      </tr>
    </tbody>
  </table>
</form>

And in the JS we can get the related input element IDs using the htmlFor property:

var totals = document.querySelectorAll('output')

function getRelated (output) {
  return Array.from(output.htmlFor, function (elementId) {
    return output.form.elements[elementId]
  })
}

function multiplyValues (inputs) {
  return inputs.reduce(function (result, input) {
    return result * Number(input.value)
  }, 1).toFixed(2)
}

function addListeners (elements, event, callback) {
  elements.forEach(function (element) {
    element.addEventListener(event, callback)
  })
}

totals.forEach(function (total) {
  var inputs = getRelated(total)

  total.value = multiplyValues(inputs)

  addListeners(inputs, 'input', function () {
    total.value = multiplyValues(inputs)
  })
})
3 Likes

Oh my god, is it true? Has the day come when we don’t need to worry about Internet Explorer failing to support better techniques anymore?

2 Likes

@Paul_Wilkins, @Paul_Wilkins

Below are the recommended layout given by my teacher. Do u guys have any idea on how to implement this? If possible, can u pls help me on that by using the same code that I first sent?

There’s only one button to be created in this table; this button is supposed to do all the calculations required. At the same time, there’s only one function that’s needed to calculate the totals and grand total. The trick here is to collect the values from the entered textfields using IDs. Remember, IDs are supposed to be unique to each other - that means no other HTML element can have each other’s IDs. For example, if you gave one of your HTML elements the ID “tf01”, no other HTML element can have the ID “tf01”.
There’s a trick if you want to play with multiple IDs. Observe the following code:

let grandTotal = 0;
for(let i = 1; i <= 3; ++i) {
    grandTotal += document.getElementById("total" + i).value;
    // for each iteration in this for-loop, the values from where the ID is either "total1", 
    // "total2" and "total3" are added in their separate iterations
}

I hope so!!

1 Like

Ahh well, when it comes to helping people with their homework. we tend to get a bit rowdy here as we all attempt to chip in with the latest and possibly confusing techniques, so that your teacher might spot that you weren’t doing the work yourself.

However having said that, we’ll happily provide theory and attempt to explain certain specific things that yhou might need to know about to help you make further progress.

1 Like

[offtopic]

[/offtopic]

2 Likes

Is that satire?

I suspect not, but the section saying: "ALSO: Microsoft says you shouldn’t buy its awful software " makes it difficult to tell.

1 Like

@Paul_Wilkins sure, not a problem. I understand that.

How to use a for loop to run the Javascript for the code below without using different id tags for each input?

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="styles.css">
    <link href="https://fonts.googleapis.com/css2?family=Lobster&family=Pathway+Gothic+One&display=swap" rel="stylesheet">
    <title>Book Ordering System</title>
    <style>

        body{
            background-image: linear-gradient(to right,#FF7F50,#008080);
        }
        thead,
        tfoot {
            background-color: skyblue;
        }

        tbody td:nth-child(5) input,
        tbody td:nth-child(6) input,
        tbody td:nth-child(7) input {
            text-align: right;

        }

        tr:hover {
            background-color: yellow;
        }

        td:last-of-type input {
            background-color: silver;
        }

        tfoot,
        tfoot input {
            text-align: right;
        }

        tfoot td:last-of-type input {
            font-size: 18pt;
        }
        table{
            border-style: dashed;
            border-width: medium;
            border-color: #EEE8AA;
        }
        tbody td:nth-child(5) input,
        tbody td:nth-child(6) input{
            background-color: tomato;
        }
        tbody td:nth-child(2) input{
            background-color: #00FF7F;
        }
        tbody td:nth-child(3) input{
            background-color: #EE82EE;
        }
        tbody td > select{
            background-color: #FFA500;
        }
        table:active {
            background-color: green;
        }
        h1{
            font-family: 'Lobster', cursive;
        }
        thead th{
            font-family: 'Pathway Gothic One', sans-serif;
            color: #CD5C5C;
        }
    </style>
</head>

<body>
    <h1>Book Ordering System</h1>
    <form method="post">
        <table border="2">
            <thead>
                <tr>
                    <th>No.</th>
                    <th>Book Title</th>
                    <th>Author</th>
                    <th>Category</th>
                    <th>Unit Price</th>
                    <th>Quantity</th>
                    <th>Total</th>
                </tr>
            </thead>
            <tfoot>
                <tr>
                    <td colspan="5">
                        <input type="button"  onclick="calculateTotal();" value="Calculate Grand Total Price">
                    </td>
                    <td colspan="2">
                        <input type="text" name="grandTotal" id="grandTotal" value="0.00" readonly="readonly">
                    </td>
                </tr>
            </tfoot>
            <tbody>
                <tr>
                    <td>1</td>
                    <td>
                        <label for="sec1"></label>
                        <input type="text" name="sec1" id="sec1" value="" />
                    </td>
                    <td>
                        <label for="sec2"></label>
                        <input type="text" name="sec2" id="sec2" value="" />
                    </td>
                    <td>
                        <select name="category" id="category">
                            <option value="choose">Please choose the category...</option>
                            <option value="biz">Business</option>
                            <option value="fiction">Fiction</option>
                            <option value="maths">Mathematics</option>
                            <option value="tech">Technology</option>
                        </select>
                    </td>
                    <td>
                        <label for="sec3"></label>
                        <input type="text" name="sec3" id="sec3" value="0.00" />
                    </td>
                    <td>
                        <label for="sec4"></label>
                        <input type="text" name="sec4" id="sec4" value="0" />
                    </td>
                    <td>
                        <label for="sec5"></label>
                        <input type="text" name="sec5" id="sec5" value="0.00" readonly="readonly" />
                    </td>
                </tr>
                <tr>
                    <td>2</td>
                    <td>
                        <label for="sec1"></label>
                        <input type="text" name="sec6" id="sec6" value="" />
                    </td>
                    <td>
                        <label for="sec2"></label>
                        <input type="text" name="sec7" id="sec7" value="" />
                    </td>
                    <td>
                        <select name="category" id="category">
                            <option value="choose">Please choose the category...</option>
                            <option value="biz">Business</option>
                            <option value="fiction">Fiction</option>
                            <option value="maths">Mathematics</option>
                            <option value="tech">Technology</option>
                        </select>
                    </td>

                    <td>
                        <label for="sec3"></label>
                        <input type="text" name="sec8" id="sec8" value="0.00" />
                    </td>
                    <td>
                        <label for="sec4"></label>
                        <input type="text" name="sec9" id="sec9" value="0" />
                    </td>
                    <td>
                        <label for="sec5"></label>
                        <input type="text" name="sec10" id="sec10" value="0.00" readonly="readonly" />
                    </td>
                </tr>
                <tr>
                    <td>3</td>
                    <td>
                        <label for="sec1"></label>
                        <input type="text" name="sec11" id="sec11" value="" />
                    </td>
                    <td>
                        <label for="sec2"></label>
                        <input type="text" name="sec12" id="sec12" value="" />
                    </td>
                    <td>
                        <select name="category" id="category">
                            <option value="choose">Please choose the category...</option>
                            <option value="biz">Business</option>
                            <option value="fiction">Fiction</option>
                            <option value="maths">Mathematics</option>
                            <option value="tech">Technology</option>
                        </select>
                    </td>
                    <td>
                        <label for="sec3"></label>
                        <input type="text" name="sec13" id="sec13" value="0.00" />
                    </td>
                    <td>
                        <label for="sec4"></label>
                        <input type="text" name="sec14" id="sec14" value="0" />
                    </td>
                    <td>
                        <label for="sec5"></label>
                        <input type="text" name="sec15" id="sec15" value="0.00" readonly="readonly" />
                    </td>
                </tr>
                <tr>
                    <td>4</td>
                    <td>
                        <label for="sec1"></label>
                        <input type="text" name="sec16" id="sec16" value="" />
                    </td>
                    <td>
                        <label for="sec2"></label>
                        <input type="text" name="sec17" id="sec17" value="" />
                    </td>
                    <td>
                        <select name="category" id="category">
                            <option value="choose">Please choose the category...</option>
                            <option value="biz">Business</option>
                            <option value="fiction">Fiction</option>
                            <option value="maths">Mathematics</option>
                            <option value="tech">Technology</option>
                        </select>
                    </td>
                    <td>
                        <label for="sec3"></label>
                        <input type="text" name="sec18" id="sec18" value="0.00" />
                    </td>
                    <td>
                        <label for="sec4"></label>
                        <input type="text" name="sec19" id="sec19" value="0" />
                    </td>
                    <td>
                        <label for="sec5"></label>
                        <input type="text" name="sec20" id="sec20" value="0.00" readonly="readonly" />
                    </td>
                </tr>
                <tr>
                    <td>5</td>
                    <td>
                        <label for="sec1"></label>
                        <input type="text" name="sec21" id="sec21" value="" />
                    </td>
                    <td>
                        <label for="sec2"></label>
                        <input type="text" name="sec22" id="sec22" value="" />
                    </td>
                    <td>
                        <select name="category" id="category">
                            <option value="choose">Please choose the category...</option>
                            <option value="biz">Business</option>
                            <option value="fiction">Fiction</option>
                            <option value="maths">Mathematics</option>
                            <option value="tech">Technology</option>
                        </select>
                    </td>
                    <td>
                        <label for="sec3"></label>
                        <input type="text" name="sec23" id="sec23" value="0.00" />
                    </td>
                    <td>
                        <label for="sec4"></label>
                        <input type="text" name="sec24" id="sec24" value="0" />
                    </td>
                    <td>
                        <label for="sec5"></label>
                        <input type="text" name="sec25" id="sec25" value="0.00" readonly="readonly" />
                    </td>
                </tr>
            </tbody>
        </table>
    </form>
    <script>
        function calculateTotal(){

            let total = 0;

            let num1 = document.getElementById("sec3").value ;
            let num2 = document.getElementById("sec4").value ;
            document.getElementById("sec5").value = (num1 * num2).toFixed(2);
            total += (num1 * num2);

            num1 = document.getElementById("sec8").value ;
            num2 = document.getElementById("sec9").value ;
            document.getElementById("sec10").value = (num1 * num2).toFixed(2);
            total += (num1 * num2);

            num1 = document.getElementById("sec13").value ;
            num2 = document.getElementById("sec14").value ;
            document.getElementById("sec15").value = (num1 * num2).toFixed(2);
            total += (num1 * num2);

            num1 = document.getElementById("sec18").value ;
            num2 = document.getElementById("sec19").value ;
            document.getElementById("sec20").value = (num1 * num2).toFixed(2);
            total += (num1 * num2);

            num1 = document.getElementById("sec23").value ;
            num2 = document.getElementById("sec24").value ;
            document.getElementById("sec25").value = (num1 * num2).toFixed(2);
            total += (num1 * num2);

            document.getElementById("grandTotal").value = total.toFixed(2);
        }
        
       </script>
</body>

</html>

You can reuse the code from my post at The value of total price changes on the first row only - #4 by Paul_Wilkins to achieve that.

My code to help someone with their homework has now helped multiple people. Bonus!

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.