toFixed implementation help

B

BC

I have read the FAQ and the discussions but I am not a Javascript
programmer and do not know how to make toFixed (and other techniques)
work, after several attempts.

The following calculations work when the form is submitted (and maybe
they should not...), but I do not know how to add a Rounding function
to the existing code, so that each Result is Rounded to 2 decimal
places.

toFixed sounds like it would be ideal...

<input type="submit" value="Submit CCI - for Maximum of 10 Items"
name="SubmitCCI001"
onClick="
this.form._15_1_Total.value = ((this.form._13_1_Quantity.value -
0) * (this.form._14_1_UnitPrice.value - 0));
this.form._15_2_Total.value = ((this.form._13_2_Quantity.value -
0) * (this.form._14_2_UnitPrice.value - 0));
this.form._15_3_Total.value = ((this.form._13_3_Quantity.value -
0) * (this.form._14_3_UnitPrice.value - 0));
this.form._15_4_Total.value = ((this.form._13_4_Quantity.value -
0) * (this.form._14_4_UnitPrice.value - 0));
this.form._15_5_Total.value = ((this.form._13_5_Quantity.value -
0) * (this.form._14_5_UnitPrice.value - 0));
this.form._15_6_Total.value = ((this.form._13_6_Quantity.value -
0) * (this.form._14_6_UnitPrice.value - 0));
this.form._15_7_Total.value = ((this.form._13_7_Quantity.value -
0) * (this.form._14_7_UnitPrice.value - 0));
this.form._15_8_Total.value = ((this.form._13_8_Quantity.value -
0) * (this.form._14_8_UnitPrice.value - 0));
this.form._15_9_Total.value = ((this.form._13_9_Quantity.value -
0) * (this.form._14_9_UnitPrice.value - 0));
this.form._15_10_Total.value = ((this.form._13_10_Quantity.value
- 0) * (this.form._14_10_UnitPrice.value - 0));
this.form._17_InvoiceTotal.value = ((this.form._15_1_Total.value - 0) +
(this.form._15_2_Total.value - 0) + (this.form._15_3_Total.value - 0) +
(this.form._15_4_Total.value - 0) + (this.form._15_5_Total.value - 0) +
(this.form._15_6_Total.value - 0) + (this.form._15_7_Total.value - 0) +
(this.form._15_8_Total.value - 0) + (this.form._15_9_Total.value - 0) +
(this.form._15_10_Total.value - 0));
">

Thank you for your patience, Bryan
 
D

Dietmar Meier

BC said:
<input type="submit" value="Submit CCI - for Maximum of 10 Items"
name="SubmitCCI001"
onClick="
this.form._15_1_Total.value = ((this.form._13_1_Quantity.value -
0) * (this.form._14_1_UnitPrice.value - 0));
this.form._15_2_Total.value = ((this.form._13_2_Quantity.value -
0) * (this.form._14_2_UnitPrice.value - 0));
this.form._15_3_Total.value = ((this.form._13_3_Quantity.value -
0) * (this.form._14_3_UnitPrice.value - 0));
this.form._15_4_Total.value = ((this.form._13_4_Quantity.value -
0) * (this.form._14_4_UnitPrice.value - 0));
this.form._15_5_Total.value = ((this.form._13_5_Quantity.value -
0) * (this.form._14_5_UnitPrice.value - 0));
this.form._15_6_Total.value = ((this.form._13_6_Quantity.value -
0) * (this.form._14_6_UnitPrice.value - 0));
this.form._15_7_Total.value = ((this.form._13_7_Quantity.value -
0) * (this.form._14_7_UnitPrice.value - 0));
this.form._15_8_Total.value = ((this.form._13_8_Quantity.value -
0) * (this.form._14_8_UnitPrice.value - 0));
this.form._15_9_Total.value = ((this.form._13_9_Quantity.value -
0) * (this.form._14_9_UnitPrice.value - 0));
this.form._15_10_Total.value = ((this.form._13_10_Quantity.value
- 0) * (this.form._14_10_UnitPrice.value - 0));
this.form._17_InvoiceTotal.value = ((this.form._15_1_Total.value - 0)
+ (this.form._15_2_Total.value - 0) + (this.form._15_3_Total.value -
0) + (this.form._15_4_Total.value - 0) + (this.form._15_5_Total.value
- 0) + (this.form._15_6_Total.value - 0) +
(this.form._15_7_Total.value - 0) + (this.form._15_8_Total.value - 0)
+ (this.form._15_9_Total.value - 0) + (this.form._15_10_Total.value -
0)); ">

<input type="submit" value="Submit CCI - for Maximum of 10 Items"
name="SubmitCCI001" onclick="calculateForm(this.form)">
[...]
function calculateForm(oForm) {
var i, sum = 0, qty, prc, sbt;
for (i=1; i<=10; i++) {
qty = oForm.elements["_13_" + i + "_Quantity"].value;
prc = oForm.elements["_14_" + i + "_UnitPrice"].value;
sbt = (isNaN(qty) || isNaN(prc))? 0 : toFixed2(qty * prc);
oForm.elements["_15_" + i + "_Total"].value = sbt;
sum += sbt;
}
oForm.elements["_17_InvoiceTotal.value"] = toFixed2(sum);
}

function toFixed2(x) {
if (Number().toFixed) return Number(x).toFixed(2);
var k = (Math.round(x * 100) / 100).toString();
k += (k.indexOf('.') == -1)? '.00' : '00';
return k.substring(0, k.indexOf('.') + 3);
}

ciao, dhgm
 
D

Dr John Stockton

JRS: In article <[email protected]>, dated Wed, 27 Apr
2005 18:14:09, seen in Dietmar Meier
function toFixed2(x) {
if (Number().toFixed) return Number(x).toFixed(2);
var k = (Math.round(x * 100) / 100).toString();
k += (k.indexOf('.') == -1)? '.00' : '00';
return k.substring(0, k.indexOf('.') + 3);
}

(a) as code for the no-toFixed case must be provided (because toFixed is
not widely enough native) and as it is very probable that the result
will be displayed and so calculation speed is not vital, is it really
worth bothering with toFixed at all?

(b) toFixed is reliably said to have bugs, but I don't know whether any
apply to toFixed(2) -
<URL:http://www.merlyn.demon.co.uk/js-round.htm#toF>

(c) the coded conversion will fail for very large numbers, where
toString uses e-format; if numbers may be very large, then k could be
returned as result if it contains an e (better to give right number in
wrong format than to give wrong- or non- number, IMHO).
 
R

RobG

BC said:
Thank you Dietmar for trying to bring me out of the dark ages.
I copied the functions into the <Head> of the HTML between
<script type="text/javascript">
</script> tags
at http://www.iconcustoms.com/cci-001.html
and it will not compute.
Cheers, Bryan
Just a comment:

You seem to be doing these calculations on the client purely for the
sake of sending them to the server. If they work as (I think) they
are designed, the user will never see the results.

In that case, why do the calculations on the client at all?

A second reason to not bother rounding is that if your users have
JavaScript disabled, the form will submit anyway without your script
running, so you have to handle data that hasn't been processed on the
client anyway.

If you want to do some processing of input that the user will see
(and they should be allowed to see modifications you have made to the
form), use onblur or onchange or similar function. It may even be
best to use an 'Update form' button so the user can run the update
when they are ready so as not to be pestered by alerts, etc. when
they are trying to fill in the form and make occasional keystroke
errors.

But always remember that any JavaScript may not have run when the
form is submitted.

Here's a sample based on your form and Dietmar's stuff.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html><head>
<meta http-equiv="Content-Type"
content="text/html; charset=ISO-8859-1">
<title>Sample form</title>
<style type="text/css">
body
{ font-family: geneva, verdana, arial, sans-serif;
background-color: #f1f1f9; color: black;}
table
{ border-collapse: collapse; border: 1px solid #aaaadd;
font-size: 90%;}
td
{vertical-align: bottom; border: 1px solid #aaaadd;}
..tip
{font-weight: normal; font-size: 80%; color: #444444;}
</style>

<script type="text/javascript">
function calcTotal(ele) {
var v = ele.value;
var oForm = ele.form;

// Get the bits of the name
var nBit = ele.name.split("_");

// Check UnitPrice is valid currency number
if ('UnitPrice' == nBit[3] ){
if ( !checkCurrency(v) && '' != v ) {
alert('Please use valid currency values' +
'\nlike 34 or 34.50');
if (ele.focus) ele.focus();
return;
}
// Check Quantity is an integer
} else if ('Quantity' == nBit[3] ){
if ( !checkQuantity(v) && '' != v ) {
alert('Quantity must be a whole number');
if (ele.focus) ele.focus();
return;
}
}

// Do calcs for line totals
var sum = 0, qty, prc, sbt;
qty = oForm.elements["_13_" + nBit[2] + "_Quantity"].value;
prc = oForm.elements["_14_" + nBit[2] + "_UnitPrice"].value;
sbt = (isNaN(qty) || isNaN(prc))? 0 : toFixed2(qty * prc);
oForm.elements["_15_" + nBit[2] + "_Total"].value = sbt;

// Update form total
oForm.elements["_17_InvoiceTotal"].value = toFixed2(totF(oForm));
}

function toFixed2(x) {
if (Number().toFixed) return Number(x).toFixed(2);
var k = (Math.round(x * 100) / 100).toString();
k += (k.indexOf('.') == -1)? '.00' : '00';
return k.substring(0, k.indexOf('.') + 3);
}

function initForm(f){
// Add onblur function where appropriate
var el = document.forms[f].elements;
var i = el.length;
while (i--){
if ( 'text' == el.type
&& ( /_Quantity/.test(el.name)
|| /_UnitPrice/.test(el.name) ) ) {
el.onblur = function () {calcTotal(this);};
} else if ( '_17_InvoiceTotal' == el.name
|| ('text' == el.type
&& /_Total/.test(el.name)) ){
el.readOnly = true;
}
}
}

function checkCurrency(x){
return /^\d+(.\d\d)?$/.test(x);
}

function checkQuantity(x){
return /^\d+$/.test(x);
}

function totF(f){
var el = f.elements;
var i = el.length;
var subt = 0;
while (i--){
if ( /_Total/.test(el.name) ){
subt += +el.value;
}
}
return subt;
}
window.onload = function() {initForm('form1')};

</script>
</head>

<body>
<form action="" name="form1">
<table>
<tr>
<th>#</th>
<th>Number of Packages</th>
<th>Specification</th>
<th>Quantity<br><span class="tip">(whole number)</span></th>
<th>Unit price<br><span class="tip">(0.00)</span></th>
<th>Total<script type="text/javascript">
// Write 'calculated' only if script supported
document.write("<br><span"
+ " class='tip'>(calculated)</" + "span>");
</script></th>
</tr><tr>
<td style="width: 38px"><b>1</b></td>
<td style="width: 78px"><input name="_11_1_NumberPackages"
size="5" type="text"></td>
<td style="width: 281px"><input
name="_12_1_SpecificationCommodities" size="35"
type="text"></td>
<td style="width: 165px"><input name="_13_1_Quantity"
size="10" type="text">
<select size="1" name="_13_1_QuantityUnits">
<option selected="selected" value="PCS">PCS</option>
<option value="DOZ">DOZ</option>
</select></td>
<td style="width: 91px">
<select size="1" name="_14_1_UnitPriceCurrency">
<option selected="selected" value="USD">USD</option>
<option value="CDN">CDN</option>
</select><br>
<input name="_14_1_UnitPrice" size="10" type="text"></td>
<td style="width: 102px"><input name="_15_1_Total"
size="10" type="text"></td>
</tr><tr>
<td><b>2</b></td>
<td><input name="_11_2_NumberPackages"
size="5" type="text"></td>
<td><input name="_12_2_SpecificationCommodities"
size="35" type="text"></td>
<td><input name="_13_2_Quantity" size="10" type="text"></td>
<td><input name="_14_2_UnitPrice" size="10" type="text"></td>
<td><input name="_15_2_Total" size="10" type="text"></td>
</tr><tr>
<td colspan="4" style="text-align: center;"><input type="reset"
value="Clear all form values"></td>
<td><b>Total</b></td>
<td><input type="text" name="_17_InvoiceTotal">
</table>
</form>
</body></html>
 
D

Dietmar Meier

Dr said:
is it really worth bothering with toFixed at all?

Not at all. I've provided that function in the german JS FAQ without
if (Number().toFixed) return Number(x).toFixed(2);
for several years, without at all bothering about adding that. I added
that here, because Bryan asked "how to make toFixed [...] work" and I
didn't want to confuse him with an answer not containing toFixed().
the coded conversion will fail for very large numbers

As I recommended this only for output of currency values: in which
currency would you expect to encounter numbers of _that_ size? :)

OK, maybe the Queen of England or Mr Gates do receive their account
statements in scientific notation ...

ciao, dhgm
 
B

BC

Thanks to John and Rob.
(THIS IS A REPOST SINCE I RECEIVED A GOOGLE ERROR ON THE LAST ATTEMPT
another lesson learned...fortunately CLIPOMATIC (free) at
http://www.mlin.net/Clipomatic.shtml
helped me with some of my recovery).

John, The downsides of client side processing are understood. This is
a working prototype and there is no Server Side calculation processing
at this time. Thanks for the warning on the toFixed limitations - we
will use this a while and get feedback on any problems. I can not
speak about the value of the forms functionality but while accurate
calculations are needed there may be a need for a form where the
results are input for now (this option will be offered to the user if
they find they are having difficulties with the calculation version -
hopefully no problems. The numbers may be large but I do not have
enough examples or experience but I will mention to my client.
Here are some other Rounding Solutions that I have found:
JavaScript Number Format v1.5.3 at
http://www.mredkj.com/javascript/numberFormat.html
ToFmt object at:
http://www.chimie.fundp.ac.be/javas/js_format.html

Rob, as you know your code works for your example form. There is a
need for "non-currency" on the Unit Price since the examples I have are
as follows: 20000 PCS Unit Price of 0.043 - the answer being
(currency) 860.00 - without the rounding the answer is 859.9999999 (or
similar)
However, there is also a need for Quantities with No Unit Price
available in which case the Importer has to put in a Comment in the
Total Price column - the COMM drop down list on the Test Form below.
The calculations are done at Submission time and all values
entered/calculated are presented as a Receipt back to the user (and
emailed to wherever they wish) so that they can print the Final Input
Results.
I have created a cut down version of the Input Form (CALCULATIONS NOT
WORKING YET) so you can try it out to see the Receipt if you like at:
http://www.iconcustoms.com/calc.html

When I have some time I will try to understand and implement (ALL OF)
your much appreciated and talented efforts in assistance, Bryan
 
D

Dr John Stockton

JRS: In article <[email protected]>, dated Thu, 28 Apr
2005 14:30:03, seen in Dietmar Meier
As I recommended this only for output of currency values: in which
currency would you expect to encounter numbers of _that_ size? :)

With the price of green paper in real money drifting steadily downwards,
the US GDP in cents is already nearing the accuracy limit of an IEEE
Double. If the Dollar behaves like the Mark did in the early nineteen-
twenties, floating-point money may be reached quite quickly.

It's always wise to be aware of limits; systems sometimes reach them
unexpectedly.
 
R

RobG

Dr said:
JRS: In article <[email protected]>, dated Thu, 28 Apr
2005 14:30:03, seen in Dietmar Meier



With the price of green paper in real money drifting steadily downwards,
the US GDP in cents is already nearing the accuracy limit of an IEEE
Double. If the Dollar behaves like the Mark did in the early nineteen-
twenties, floating-point money may be reached quite quickly.

It's always wise to be aware of limits; systems sometimes reach them
unexpectedly.

Move quickly enough and perhaps you can name the currency-equivalent
of Y2k (or have it named after you) - what is the limit of common
banking/accounting packages?

Approximately when will the values in the financial domain of those
packages start to exceed their capability?

Now there's some fun...
 
R

RobG

BC wrote:
[...]
Rob, as you know your code works for your example form. There is a
need for "non-currency" on the Unit Price since the examples I have are
as follows: 20000 PCS Unit Price of 0.043 - the answer being
(currency) 860.00 - without the rounding the answer is 859.9999999 (or
similar)
However, there is also a need for Quantities with No Unit Price
available in which case the Importer has to put in a Comment in the
Total Price column - the COMM drop down list on the Test Form below.
The calculations are done at Submission time and all values
entered/calculated are presented as a Receipt back to the user (and
emailed to wherever they wish) so that they can print the Final Input
Results.

That's OK. The validation function can be modified to suit (that's
partly why it's a separate function) and the result can be used for
whatever purpose: I chose to put up an alert and message, but you
could do some other processing. A better solution is to put a
checkbox for your exceptions, otherwise you are guessing that a
non-numeric input is not an error but an intended entry (ah, I see
you've use a select).

The select options should either be self-explanatory or a legend
should let users know what 'COMM' (comment?) 'F.O.C.' (free of
charge?) and 'CALL' (CALC? - calculated?) mean.

You could put three inputs in the cell, then enable & display
whichever one corresponds to the selected option - that would greatly
simplify form processing and the users could get a visual cue as to
what they should enter or what they have selected.
I have created a cut down version of the Input Form (CALCULATIONS NOT
WORKING YET) so you can try it out to see the Receipt if you like at:
http://www.iconcustoms.com/calc.html

Another thing I'd hope you'd pick up from the example was the
application of styles. Instead of:

<td width="38" bgcolor="#F1F1F9" style="font-family: Arial, Verdana,
Geneva, sans-serif">

on every single td, use CSS to set all td's to that style (see my
example). Similarly with column (td) widths. You only need set them
once. It is then much easier to maintain as you only need modify one
value for each column, not one for every row of every column.

But I guess that can be better covered in a CSS group...
 
B

BC

Deitmar, your code is working beautifully for the line items now that I
have eliminated 2 extraneous characters (looked like a - sign in the
middle of 2 words appearing like
fo-rm
Tot-al
and I even tried it without my Clipomatic Clipboard program running
oForm.elements["_17_InvoiceTot­al.value"] = toFixed2(sum);
is not producing a result
http://www.iconcustoms.com/calc.html
I did get an error from the Microsoft Script Editor (for Jscript not
Javascript) saying
elements is Null or Not an Object - but that has stopped when I run it
locally.
I have retyped those 2 words but can not see anything else - and only
in some circumstances could I see it anyway - inside the Jscript Editor
and when I pasted into the Subject line of my email editor the
following
onclick="calculateForm(this.fo­rm)">
I know that if I knew Javascript I might know what to look for, but...
Do you mind sending the code to me directly to see if that will help
Thx, BC.
 
D

Dietmar Meier

BC said:
oForm.elements["_17_InvoiceTot­al.value"] = toFixed2(sum);
is not producing a result

Of course that's an obvious mistake I made, replace it with
oForm.elements["_17_InvoiceTot­al"].value = toFixed2(sum);

Sorry for not telling that it was an untested quickhack.

ciao, dhgm
 
B

BC

No sorries required - I should have seen that difference, and thanks.
Now getting NaN as a result...with a Form Validation Error of "Please
enter only digit characters in the "_17_InvoiceTotal" field"
Checked that the field formatting is identical to the individual line
Totals - that is Numeric with . and , separators. Also ensured numbers
in all line items as well but still did not work at:
http://www.iconcustoms.com/calc.html
Take care, BC
 
D

Dietmar Meier

BC said:
Now getting NaN as a result...

I don't have much time at the moment, so I overlooked another
problem. As I said, I didn't find any time to test all that.
Try replacing
sum += sbt;
with
sum += +sbt;
or
sum += Number(sbt);
to correct this mistake.

ciao, dhgm
 
B

BC

Fantastic...both techniques worked. Thanks Dietmar. And thanks to
Rob; and some of the layout suggestions have been taken but no CSS yet
- although I strive to increase my knowledge here as well. And to
John...I have asked the client to put the calculations to the test
using the largest numbers they have ever seen and then some...will let
you all know how that works out. The "final" product - Version 1 is
at:
http://www.iconcustoms.com/CCI-001.html
and the test version which anyone can try is at
http://www.iconcustoms.com/calc.html
From my point of view I consider this topic closed, Bryan Cronk (BC)
www.bc-solutions.com from Bass Lake near Perth, Ontario, Canada
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,143
Latest member
SterlingLa
Top