I'm very new to JavaScript, so I'm not sure how to optimize the following code (which seems to run fine) further, though I did try to implement a few tips found on the web — such as using local variables for document elements, using do/while loops instead of for, or using join
for string concatenation. I've read about using object literal instead of arrays, but I have to investigate further this point.
The script updates the displayed price on an HTML5 webpage when the client selects options. It is limited to radio, checkboxes and select input types. Each time one of these change, updatePrice()
is called via onclick
. The final price is to be updated, as well as discount thresholds (the more you order, the lesser the price).
Most variables are initialized from PHP (using <?php echo $opencart_variable; ?>
, as for the HTML), hence the somehow unnatural "option[228]" form (it's not very relevant here but the script is intended as a (free) OpenCart extension). I'm open for suggestions on how to improve this, including switching to numbers, though I'm not sure I would implement them (in the "official" version of the extension, at least) since it may require large modifications of the theme and robustness of the extension depends on its intrusiveness.
var allOptionsValues = new Array(); // better solution ?
allOptionsValues["option[229]"] = new Array();
allOptionsValues["option[229]"]["21"] = 1.22;
allOptionsValues["option[229]"]["22"] = 0;
allOptionsValues["option[229]"]["23"] = 2.42;
allOptionsValues["option[228]"] = new Array();
allOptionsValues["option[228]"]["19"] = 1.22;
allOptionsValues["option[228]"]["20"] = 2.42;
var basicPrice = 12.14;
var currencyLeft = "";
var currencyRight = " €";
var decimalPoint = ",";
var discountThresholds = [];
var discountPrices = [];
discountThresholds.push(5);
discountPrices.push(9.14);
discountThresholds.push(10);
discountPrices.push(7.94);
discountThresholds.push(15);
discountPrices.push(6.74);
var discountText = " ou plus ";
var thisPage = document;
var quantity = thisPage.getElementById("input-quantity");
var optionsDiv = thisPage.getElementById("product");
var allInputs = optionsDiv.getElementsByTagName("input");
var allSelects = optionsDiv.getElementsByTagName("select");
var allDiscounts = thisPage.getElementsByClassName("discountPrice");
var priceList = thisPage.getElementsByClassName("finalPrice");
var nInputs = allInputs.length;
var nSelects = allSelects.length;
var nDiscounts = discountThresholds.length;
var nPrices = priceList.length;
var nProducts = 1;
var epsilon = 0.00001;
var newDiscountPrice = new Array(nDiscounts);
var newPrice = basicPrice;
function setPrices(delta)
{
newPrice += delta;
var i = nDiscounts;
do {
newDiscountPrice[i] += delta;
} while (i--);
}
function updatePrice()
{
// options prices will be added to (or removed from) the basic prices
newPrice = basicPrice;
var i = nDiscounts;
do {
newDiscountPrice[i] = discountPrices[i];
} while (i--);
// get number of products
nProducts = quantity.value;
// is a discount allowed for the current quantity ?
for (i = 0; i < nDiscounts; ++i)
{
if (nProducts < discountThresholds[i])
break;
newPrice = discountPrices[i];
}
// loop on all input fields, update price and set quantity (assuming there is only one text/number field)
i = nInputs - 1;
do {
var thisOpt = allInputs[i];
if (thisOpt.checked)
setPrices(allOptionsValues[thisOpt.name][thisOpt.value]);
} while (i--);
// loop on select fields, update price
i = nSelects - 1;
do {
var thisSel = allSelects[i];
if (thisSel.selectedIndex > 0)
setPrices(allOptionsValues[thisSel.name][thisSel.options[thisSel.selectedIndex].value]);
} while (i--);
// update display of discount prices
i = nDiscounts - 1;
do {
allDiscounts[i].innerHTML = [discountThresholds[i], discountText, currencyLeft, (newDiscountPrice[i]+epsilon).toFixed(2).replace('.', decimalPoint), currencyRight].join('');
} while (i--);
// update display of current price
i = nPrices - 1;
do {
// priceList[i].innerHTML = [currencyLeft, (nProducts*newPrice+epsilon).toFixed(2).replace('.', decimalPoint), currencyRight].join(''); // faster than concatenation // TOTAL PRICE
priceList[i].innerHTML = [currencyLeft, (newPrice+epsilon).toFixed(2).replace('.', decimalPoint), currencyRight].join(''); // faster than concatenation // PRICE PER UNIT
} while (i--);
}