Jump to content

Archived

This topic is now archived and is closed to further replies.

djmonkey1

Trying to use javascript on a dynamically generated array

Recommended Posts

Here's the scenario:

 

I'm working on an update of Order Editor (http://www.oscommerce.com/community/contributions,1435) with a neato little calcuator function like in categories.php for calculating price with tax (net and gross).

 

It would work on each individual piece in the order (just the final price and the price with tax at first, once I get this to work then I can throw quantity into the mix and go completely nuts).

 

It seemed to my addled brain that the best way to go would be to have PHP dynamically generate the javascript with unique functions for each product, so the javascript would know which price was which when it was doing the calculations.

 

So I came up with this:

 

<script language="javascript"><!--

 function doRound(x, places) {
return Math.round(x * Math.pow(10, places)) / Math.pow(10, places);
}

<?php

 for ($i=0; $i<sizeof($order->products); $i++) {
 $orders_products_id = $order->products[$i]['orders_products_id'];
 if (sizeof($order->products) > 0) {
 echo '  function updatePriceIncl' . $orders_products_id . '() {' . "\n" .
   '	var taxRate = document.forms["edit_order"].update_products[' . $orders_products_id . '][tax].value;' . "\n" .
   '	var priceInclValue = document.forms["edit_order"].update_products[' . $orders_products_id . '][final_price].value;' . "\n\n" .
   '	if (taxRate != 0) {' . "\n" . 
   '	  priceInclValue = priceInclValue * ((taxRate / 100) + 1);' . "\n" . 
   '	}' . "\n\n" . 
   '	document.forms["edit_order"].update_products[' . $orders_products_id . '][price_incl].value = doRound(priceInclValue, 4);' . "\n" . 
   '  }'. "\n\n";

 echo '  function updatePriceExcl' . $orders_products_id . '() {' . "\n" .
   '	var taxRate = document.forms["edit_order"].update_products[' . $orders_products_id . '][tax].value;' . "\n" .
   '	var priceExclValue = document.forms["edit_order"].update_products[' . $orders_products_id . '][price_incl].value;' . "\n\n" .
   '	if (taxRate != 0) {' . "\n" . 
   '	  priceExclValue = priceExclValue * ((taxRate / 100) + 1);' . "\n" . 
   '	}' . "\n\n" . 
   '	document.forms["edit_order"].update_products[' . $orders_products_id . '][final_price].value = doRound(priceExclValue, 4);' . "\n" . 
   '  }'. "\n\n";
}
}
	?>

//--></script>

 

That generates javascript that for an individual product looks like this:

 

function updatePriceIncl209() {
var taxRate = document.forms["edit_order"].update_products[209][tax].value;
var priceInclValue = document.forms["edit_order"].update_products[209][final_price].value;

if (taxRate != 0) {
  priceInclValue = priceInclValue * ((taxRate / 100) + 1);
}

document.forms["edit_order"].update_products[209][price_incl].value = doRound(priceInclValue, 4);
 }

 function updatePriceExcl209() {
var taxRate = document.forms["edit_order"].update_products[209][tax].value;
var priceExclValue = document.forms["edit_order"].update_products[209][price_incl].value;

if (taxRate != 0) {
  priceExclValue = priceExclValue * ((taxRate / 100) + 1);
}

document.forms["edit_order"].update_products[209][final_price].value = doRound(priceExclValue, 4);
 }

 

with the corresponding inputs lines looking like this:

 

<td class="dataTableContent" valign="top"><input name="update_products[209][tax]" size="6" value="17.7000" onkeyup="updatePriceIncl209()"></td>
<td class="dataTableContent" align="right" valign="top"><input name="update_products[209][final_price]" size="7" value="12.9876" onkeyup="updatePriceIncl209()"></td>
<td class="dataTableContent" align="right" valign="top"><input name="update_products[209][price_incl]" size="7" value="15.2864" onkeyup="updatePriceExcl209()"></td>

 

But when I try to use the little bugger I get this error:

Error: 'document.forms.edit_order.update_products.209' is null or not an object

Code: 0

 

It looks like it's failing on the products_id number. ???

 

Also, is there a cleaner way to do this? For a large order the javascript section would be enormous.


Do, or do not. There is no try.

 

Order Editor 5.0.6 "Ultra Violet" is now available!

For support or to post comments, suggestions, etc, please visit the Order Editor support thread.

Share this post


Link to post
Share on other sites

I think the problem is in that the input name can't contain [] characters. Javascript thinks it is an array and is looking for the 209th item of that array varible and it doesn't exist. Javascript I can do, mostly. But oscommerce programming is over my head.

 

A good javascript forum is http://www.codingforums.com/

 

CP

Share this post


Link to post
Share on other sites
I think the problem is in that the input name can't contain [] characters. Javascript thinks it is an array and is looking for the 209th item of that array varible and it doesn't exist. Javascript I can do, mostly. But oscommerce programming is over my head.

 

A good javascript forum is http://www.codingforums.com/

 

CP

 

So we know that there's nothing really wrong with the javascript, just that it doesn't recognize the information in brackets as static data.

 

I came up with the idea to change the input names. Where I used to have this:

 

input name='update_products[$orders_products_id][tax]'

 

I now have this:

 

input name='tax_" . $orders_products_id . "'

 

Of course, now the form won't work.

 

Is it possible to put a switch in the code so that it knows that

input name='tax_" . $orders_products_id . "'

is the same as

input name='update_products[$orders_products_id][tax]'

?


Do, or do not. There is no try.

 

Order Editor 5.0.6 "Ultra Violet" is now available!

For support or to post comments, suggestions, etc, please visit the Order Editor support thread.

Share this post


Link to post
Share on other sites

try to use one jscript function instead and either pass the $order_products_id as the parameter to it, or iterate the form and apply the tax calculation to each form element (because you have the price on the element already). use .type in your loop so you can check for the input elements.

 

also you dont need this if as its already checked in the for loop so its redundant.

if (sizeof($order->products) > 0) {

}

Share this post


Link to post
Share on other sites
try to use one jscript function instead and either pass the $order_products_id as the parameter to it, or iterate the form and apply the tax calculation to each form element (because you have the price on the element already). use .type in your loop so you can check for the input elements.

 

also you dont need this if as its already checked in the for loop so its redundant.

if (sizeof($order->products) > 0) {

}

 

Thanks for the tips- what I ended up doing was putting the input name inside brackets and quotes as in this example:

 

var taxRate = document.forms.edit_order["update_products[209][tax]"].value;

 

This way JavaScript reads the input name as a string instead of a multi-dimensional array, no need to re-write the PHP, and everyone's happy. Thanks to the JavaScript Bible for showing me the way- maybe I should have read it in the first place... :)

 

Are you sure this could all be done with only one JavaScript function?


Do, or do not. There is no try.

 

Order Editor 5.0.6 "Ultra Violet" is now available!

For support or to post comments, suggestions, etc, please visit the Order Editor support thread.

Share this post


Link to post
Share on other sites

yes with a single function. If you have a common form you do it at the form definition using the onsubmit handler. If you have a sequence of input fields then you could utilize the onchange handler for each edit field and do the calculations in which case you just pass one or more parameters to the same jscript function. The function in turn calculates the amounts and updates the necessary fields of the form on the fly.

Share this post


Link to post
Share on other sites
yes with a single function. If you have a common form you do it at the form definition using the onsubmit handler. If you have a sequence of input fields then you could utilize the onchange handler for each edit field and do the calculations in which case you just pass one or more parameters to the same jscript function. The function in turn calculates the amounts and updates the necessary fields of the form on the fly.

 

What I've currently got for one products looks like this:

 

function updatePriceIncl209() {
var taxRate = document.forms.edit_order["update_products[209][tax]"].value;
var qty = document.forms.edit_order["update_products[209][qty]"].value;
var priceInclValue = document.forms.edit_order["update_products[209][final_price]"].value;

if (taxRate != 0) {
  priceInclValue = priceInclValue * ((taxRate / 100) + 1);
}

document.forms.edit_order["update_products[209][price_incl]"].value = doRound(priceInclValue, 4);
 }

 function updatePriceExcl209() {
var taxRate = document.forms.edit_order["update_products[209][tax]"].value;
var qty = document.forms.edit_order["update_products[209][qty]"].value;
var priceExclValue = document.forms.edit_order["update_products[209][total_excl]"].value;

  priceExclValue = priceExclValue / qty;

document.forms.edit_order["update_products[209][final_price]"].value = doRound(priceExclValue, 4);
 }

 function updateTotalIncl209() {
var taxRate = document.forms.edit_order["update_products[209][tax]"].value;
var qty = document.forms.edit_order["update_products[209][qty]"].value;
var totalInclValue = document.forms.edit_order["update_products[209][price_incl]"].value;

  totalInclValue = totalInclValue * qty;

document.forms.edit_order["update_products[209][total_incl]"].value = doRound(totalInclValue, 4);
 }

 function updateTotalExcl209() {
var taxRate = document.forms.edit_order["update_products[209][tax]"].value;
var qty = document.forms.edit_order["update_products[209][qty]"].value;
var totalExclValue = document.forms.edit_order["update_products[209][total_incl]"].value;

if (taxRate != 0) {
  totalExclValue = totalExclValue / ((taxRate / 100) + 1);
}

document.forms.edit_order["update_products[209][total_excl]"].value = doRound(totalExclValue, 4);
 }

 

It would be nice to do it all in four functions total (instead of four functions for every item in the order), but how? My handy JavaScript reference book isn't so handy, as far as I can tell, when it comes to accessing and using variables in js, especially when they're generated by a server-side scripting language like PHP.

 

How can I set this up so I only have to write out the four functions one time and javascript recognizes that each line is unique, preferably by using the orders_products_id?


Do, or do not. There is no try.

 

Order Editor 5.0.6 "Ultra Violet" is now available!

For support or to post comments, suggestions, etc, please visit the Order Editor support thread.

Share this post


Link to post
Share on other sites

ok have a look in the admin\categories.php There're a couple of jscript functions to update the gross price from the net.

 

function updateGross() {
 var taxRate = getTaxRate();
 var grossValue = document.forms["new_product"].products_price.value;

 if (taxRate > 0) {
grossValue = grossValue * ((taxRate / 100) + 1);
 }

 document.forms["new_product"].products_price_gross.value = doRound(grossValue, 4);
}

function updateNet() {
 var taxRate = getTaxRate();
 var netValue = document.forms["new_product"].products_price_gross.value;

 if (taxRate > 0) {
netValue = netValue / ((taxRate / 100) + 1);
 }

 document.forms["new_product"].products_price.value = doRound(netValue, 4);
}

 

Now lets say I have with multiple products where for each of them I want to update the gross from the net. So first I change the function prototype to pass parameters to them

 

function updateGross(some_element1, some_element2) {
 var taxRate = getTaxRate();
 var grossValue = document.forms["new_product"].some_element1.value;

 if (taxRate > 0) {
grossValue = grossValue * ((taxRate / 100) + 1);
 }

 document.forms["new_product"].some_element2.value = doRound(grossValue, 4);
}

function updateNet(some_element1, some_element2) {
 var taxRate = getTaxRate();
 var netValue = document.forms["new_product"].some_element1.value;

 if (taxRate > 0) {
netValue = netValue / ((taxRate / 100) + 1);
 }

 document.forms["new_product"].some_element2.value = doRound(netValue, 4);
}

 

Then you call it pretty much like in the categories.php but you pass the element name to them using the onChange handler.

Share this post


Link to post
Share on other sites
ok have a look in the admin\categories.php There're a couple of jscript functions to update the gross price from the net.

 

function updateGross() {
 var taxRate = getTaxRate();
 var grossValue = document.forms["new_product"].products_price.value;

 if (taxRate > 0) {
grossValue = grossValue * ((taxRate / 100) + 1);
 }

 document.forms["new_product"].products_price_gross.value = doRound(grossValue, 4);
}

function updateNet() {
 var taxRate = getTaxRate();
 var netValue = document.forms["new_product"].products_price_gross.value;

 if (taxRate > 0) {
netValue = netValue / ((taxRate / 100) + 1);
 }

 document.forms["new_product"].products_price.value = doRound(netValue, 4);
}

 

Now lets say I have with multiple products where for each of them I want to update the gross from the net. So first I change the function prototype to pass parameters to them

 

function updateGross(some_element1, some_element2) {
 var taxRate = getTaxRate();
 var grossValue = document.forms["new_product"].some_element1.value;

 if (taxRate > 0) {
grossValue = grossValue * ((taxRate / 100) + 1);
 }

 document.forms["new_product"].some_element2.value = doRound(grossValue, 4);
}

function updateNet(some_element1, some_element2) {
 var taxRate = getTaxRate();
 var netValue = document.forms["new_product"].some_element1.value;

 if (taxRate > 0) {
netValue = netValue / ((taxRate / 100) + 1);
 }

 document.forms["new_product"].some_element2.value = doRound(netValue, 4);
}

 

Then you call it pretty much like in the categories.php but you pass the element name to them using the onChange handler.

 

Ok-

 

I have six variables- qty, tax, final_price (aka price_excl), price_incl, total_excl, and total_incl.

 

In your scheme, as I understand it, some_element1 could be any number from 1 to infinity (the orders_products_id), and some_element2 would be one of the six variables.

 

So in the <input> tag for tax I would have onchange='updateTotals($orders_products_id, tax)', and similar handlers for the other five variables.

 

And for the javascript function I would have something like

 

function updateTotals(some_element1, some_element2) {
var taxRate = document.forms.edit_order["update_products"].some_element1.some_element2.value;
 var priceInclValue = document.forms.edit_order["update_products"].some_element1.value;
var totalInclValue = document.forms.edit_order["update_products"].some_element1.value;

if (taxRate != 0) {
  priceInclValue = priceInclValue * ((taxRate / 100) + 1);
}

  totalInclValue = totalInclValue * qty;

 document.forms.edit_order["update_products"].some_element2.value = doRound(grossValue, 4);
}

 

And js will automagically calculate new values for priceInclValue and totalInclvalue, even though the other five variables all have a unique value for some_element2?


Do, or do not. There is no try.

 

Order Editor 5.0.6 "Ultra Violet" is now available!

For support or to post comments, suggestions, etc, please visit the Order Editor support thread.

Share this post


Link to post
Share on other sites
In your scheme, as I understand it, some_element1 could be any number from 1 to infinity (the orders_products_id), and some_element2 would be one of the six variables.

well you could pass the id but in this example I was using the html element name for the parameters because I can read the html element within the jscript function.

			<td class="main"><?php echo tep_draw_separator('pixel_trans.gif', '24', '15') . ' ' . tep_draw_input_field('products_price_gross', $pInfo->products_price, 'OnKeyUp="updateNet(\'products_price_gross\',\'products_price\')"'); ?></td>

then I get the value of gross from the input field and do something with it and finally I set the products_price field. So if I had multiple products I will use the same function and simply have a different element name to pass to the function. So my input fields each one within a table cell for each product would become like

 

'OnKeyUp="updateNet(\'products_price_gross1\',\'products_price1\')"');

'OnKeyUp="updateNet(\'products_price_gross2\',\'products_price2\')"');

'OnKeyUp="updateNet(\'products_price_gross3\',\'products_price3\')"');

 

etc. So the strings will pass into the same jscript function that can apply and manipulate the contents of the input fields. So in this example everytime a key is released when you edit the gross price of each product the equivalent net price will change.

 

In contrast when you want to submit a form you use the onsubmit hadnler which can then iterate through all html elements and do something with them like validating.

Share this post


Link to post
Share on other sites
well you could pass the id but in this example I was using the html element name for the parameters because I can read the html element within the jscript function.

 

then I get the value of gross from the input field and do something with it and finally I set the products_price field. So if I had multiple products I will use the same function and simply have a different element name to pass to the function. So my input fields each one within a table cell for each product would become like

 

etc. So the strings will pass into the same jscript function that can apply and manipulate the contents of the input fields. So in this example everytime a key is released when you edit the gross price of each product the equivalent net price will change.

 

In contrast when you want to submit a form you use the onsubmit hadnler which can then iterate through all html elements and do something with them like validating.

 

How about this:

 

function doRound(x, places) {
return Math.round(x * Math.pow(10, places)) / Math.pow(10, places);
}

 function updatePrices(action, pid) {
var qty = document.getElementById(pid + "-qty").value;
var taxRate = document.getElementById(pid + "-tax").value;

if ((action == 'qty') || (action == 'tax') || (action == 'final_price')) {

var priceInclValue = document.getElementById(pid + "-final_price").value;
var totalInclValue = document.getElementById(pid + "-final_price").value;
var totalExclValue = document.getElementById(pid + "-final_price").value;

priceInclValue = priceInclValue * ((taxRate / 100) + 1);
totalInclValue = totalInclValue * ((taxRate / 100) + 1) * qty;
totalExclValue = totalExclValue * qty;

} //end of if ((action == 'qty') || (action == 'tax') || (action == 'final_price')) 

if (action == 'price_incl') {

var finalPriceValue = document.getElementById(pid + "-price_incl").value;
var totalInclValue = document.getElementById(pid + "-price_incl").value;
var totalExclValue = document.getElementById(pid + "-price_incl").value;

finalPriceValue = finalPriceValue / ((taxRate / 100) + 1);
totalInclValue = totalInclValue * qty;
totalExclValue = totalExclValue * qty / ((taxRate / 100) + 1);

} //end of if (action == 'price_incl')

if (action == 'total_excl') {

var finalPriceValue = document.getElementById(pid + "-total_excl").value;
var priceInclValue = document.getElementById(pid + "-total_excl").value;
var totalInclValue = document.getElementById(pid + "-total_excl").value;

finalPriceValue = finalPriceValue / qty;
priceInclValue = priceInclValue * ((taxRate / 100) + 1) / qty;
totalInclValue = totalInclValue * ((taxRate / 100) + 1);

} //end of if (action == 'total_excl')

if (action == 'total_incl') {

var finalPriceValue = document.getElementById(pid + "-total_incl").value;
var priceInclValue = document.getElementById(pid + "-total_incl").value;
var totalExclValue = document.getElementById(pid + "-total_incl").value;

finalPriceValue = finalPriceValue / ((taxRate / 100) + 1) / qty;
priceInclValue = priceInclValue / qty;
totalExclValue = totalExclValue / ((taxRate / 100) + 1);

} //end of if (action == 'total_incl')

if ((action != 'qty') && (action != 'tax') && (action != 'final_price')) {
document.getElementById(pid + "-final_price").value = doRound(finalPriceValue, 4);
}

if ((action != 'qty') && (action != 'price_incl')) {
document.getElementById(pid + "-price_incl").value = doRound(priceInclValue, 4);
}

if ((action != 'tax') && (action != 'total_excl')) {
document.getElementById(pid + "-total_excl").value = doRound(totalExclValue, 4);
}

if (action != 'total_incl') {
document.getElementById(pid + "-total_incl").value = doRound(totalInclValue, 4);
}

} //end function updatePrices(action, pid)


Do, or do not. There is no try.

 

Order Editor 5.0.6 "Ultra Violet" is now available!

For support or to post comments, suggestions, etc, please visit the Order Editor support thread.

Share this post


Link to post
Share on other sites

yea something like that, so the same function is used just the parameters change, each time is called.

Share this post


Link to post
Share on other sites

×