I am creating a form which dynamically creates a list of options to purchase. The list is generated from a database. The PHP is

     for($i = 1; $i <= $opt_count; $i++){
            $desc = $options['description'][$i];
            $prc = $options['price'][$i];
            $type = $options['type'][$i];
            $size[$i] = '&nbsp;';
            $option_text = <<<TABLE
                    <td style="text-align:center">$size[$i]</td>
                    <td style="text-align:center"><input type="text" name="qty[$i]" onchange="calculate()" size="2" /></td>
                    <td style="text-align:right">$prc[$i]</td>
                    <td class="right_align"><input type="text" style="text-align:right" name="total[$i]" size="2" readonly="readonly" /></td>
            echo $option_text;
        } // for loop

My problem is that I don't know how to create the JavaScript calculate() function to calculate the total for a line item, and also a grand total (an input field that is not shown in this snippet).

well.. couple things...

without knowing how you make $opt_count, Im gonna make a wild assumption that you are going to be missing an item as arrays start at 0, and you are starting $i at 1 (so your first item will be missing. If that's expected then ignore this).

As for the JS, you have script attached to "onchange" for the text field. That means when someone types in a value then moves off that field the script will fire.

However, with what you have on the page, it does not seem that you are keeping track of the price per item anywhere "usable" and your naming convention seems odd.

Instead, consider this..

 for($i = 0; $i <= $opt_count; $i++){
        $desc = $options['description'][$i];  //these seem a little weird
        $prc = $options['price'][$i];         //without seeing your data
        $type = $options['type'][$i];         //it's hard to explain why
        $size[$i] = '&nbsp;';  //?? What is this for?
        $option_text = '<tr>';
        $option_text .= '<td>$desc</td>';
        $option_text .= '<td style="text-align:center">' . $size . '</td>"';
        $option_text .= '<td style="text-align:center"><input type="text" name="qty ' . $i . '" price="' . $prc . '" onchange="calculate(this)" size="2" /></td>';

        $option_text .= '<td style="text-align:right">' . $prc . '</td>';

        $option_text .= '<td class="right_align"><input type="text" style="text-align:right" name="total' . $i . '" id="total' . $i . '" size="2" readonly="readonly" /></td>';
         $option_text .= '</tr>';
        echo $option_text;
    } // for loop

From here, since we now have a "price" attribute on the input element, we can access it via javascript and use it...

in the head of the page...

<script type="text/javascript">
function calculate(this)
  if (!this)  //if this is invoked without a root element
    return;   //stop

  var PricePer = this.getAttribute("price");  //get the price attribute
  var Count = this.value;                     //get how many we have

  if (!Count)                                 //if it's null, then make it 0
    Count = 0;

  var totalCost = PricePer * Count;           //our math

  //who do we belong to?
  var Num = this.name.replace("qty", "");     //your naming convention...
  var Elem = document.getElementById("total" + Num);  //get the total node
  if (Elem)                                   //if it exists...
    Elem.value = totalCost;                   //set its value.


Now.. you are saying you plan on having a "grand total" for this... based on how you are going about doing this right now, I would encourage you to make sure that your script is for display only, and you do all money calculations server side. Javascript is easily "hackable" and if you are relying on javascript to pass it "totals" to the server, you will find you have just sold 500 beanie babies for exactly $0.10 because each time someone let your script update they would debug and change it.

Javascript is for display only!


That said, you can use what was made above with some modifications to simply add up all the rows and fill in a field with the total value of all products.

Now, this is very simplistic in approach because I do not have the rest of your code or page to work with. If you have any further questions, feel free to ask!

Ryan :)

P.S. If the PHP is not formatted correctly it's because I did get a little lazy and didnt use an editor... it should work as is, but may need some love.

Member Avatar

I'd make a listener in the js as opposed to inline onchange.

Either way. Pick your Tool. The code is the same otherwise.


Thanks for your input. The form is a registration form for an event. Each individual event will have a different set of options The options array is derived from a database, and will have a valid price value for each line item. I am aware of the missing 0 index; that is reserved for the registration fee with a fixed quantity of 1. That part of the code works fine. Can you suggest a better format for retrieving the data?

The non-breaking space as a size value is just a placeholder in the table for line items that don't have a size (I snipped the part for picking size where it is relevant out of the code because it had nothing to do with the question at hand.)

The price attribute for the qty input is the missing link. I was trying to get the value directly from the prc variable used as a text value. I didn't know that I could assign attributes like that.

I am still a little cloudy on the "this" keyword. I don't understand how the Count variable gets a value with that definition. Can you recommend a "simple tutorial on 'this' for simple people"?

Thanks for the security warning. I will follow your recommendation.


Can you recommend a "listener" tutorial?


This in javascript can be tricky depending on its location.

<input type="text" value="" onclick="someFunction(this);"> //=> refers to the input.

<script type="text/javascript">

//outside of a function or object:
var myVar = this; //refers to window.

//in a function
function myFunction()
  var myFunc = this; //refers to the function.
//note if your function is a "class" instantiation, "this" changes scope within each method of your class. 

function myClass()
  var _that = this; //refers to function

  var myMethod = function()
    var myMethod = this; //refers to this particular function.
    _that; //refers to myClass.

  return this;  //the function and all properties.

//in an object "singleton"
var myObj = {
  someVar: this, //refers to the object.
  someMethod: function () {
    var i = 0;
    this.someVar = i; //refers to object as well...

hope that helps