Page 1 of 2 12 LastLast
Results 1 to 10 of 14

Thread: formatting for dollars

  1. #1
    Join Date
    Oct 2005
    Location
    Sierra foothills of California
    Posts
    5
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default formatting for dollars

    I have a web site I am working on that takes dynamic data (coming in from a JavaScript array) and displays it in an HTML form. The problem is, I can't find any way in HTML, XHTML, or JavaScript to format the data in the cell to a proper currency format. I want the data to gain the structure of ###,###.## where the hash marks represent a floating point value.

    I would really like to do this via JavaScript and not ASP or PHP, as I know nothing about them. One suggestion I have received is to use a scalable integer, but I'd kind of like to handle it via floating point math to make the code easier to understand and maintain.

    Any suggestions? I would think, given how currency values are so common in everyday use that something like this would exist, but I've not yet found it.

  2. #2
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    If you have commas in the output, math (at some point) is out of the question. Try various initial values for the variable tot:

    Code:
    <script type="text/javascript">
    var tot = 1000324.4
    var tot=tot.toString().replace(/,/g, '')
    tot=tot.indexOf('.')==-1? tot+='.00' : tot.length-tot.indexOf('.')==1? tot+='0' : tot
    tot=tot.split('.')
    tot[2]=''
    var count=0
    for (var i_tem = tot[0].length-1 ; i_tem > -1 ; i_tem--){
    if (count&&count%3==0)
    tot[2]+=','
    tot[2]+=tot[0].charAt(i_tem)
    count++
    }
    tot[0]=''
    for (var i_tem = tot[2].length-1 ; i_tem > -1 ; i_tem--)
    tot[0]+=tot[2].charAt(i_tem)
    tot='$'+tot[0]+'.'+Math.round(Math.abs('.'+tot[1])*100)
    tot=tot.length-tot.indexOf('.')==2? tot+='0' : tot
    alert(tot)
    </script>
    Since I don't know the full spectrum of possible initial values, their origin or how they typically get into the table cells, the above will serve as a general idea. If you need help adapting it, give me the specifics.
    Last edited by jscheuer1; 11-04-2005 at 10:05 PM.
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  3. #3
    Join Date
    Dec 2004
    Location
    UK
    Posts
    2,358
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default

    Quote Originally Posted by charlesb
    I want the data to gain the structure of ###,###.## where the hash marks represent a floating point value.
    See my toCurrency method.

    One suggestion I have received is to use a scalable integer, but I'd kind of like to handle it via floating point math to make the code easier to understand and maintain.
    Whenever money is involved, calculations should always be performed using scaled integers, with as much integer arithmetic as possible. Floating point maths is inaccurate due to the inability to accurately represent some fractional parts in base-2.

    Mike

  4. #4
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    Very interesting, Mike. It ignores the commas that the OP requested but otherwise works very well. I'm wondering how long it will take me to understand what you've done. I'll either learn a lot or give up Anyways, I got interested in this one and played around with my version a bit more. I've come up with a function that formats dollars and cents with a dollar sign, commas (if appropriate) and two decimal places, with (I believe) iron clad 'error checking' on the input for validity. In the demo below the input field activates the function 'onchange' meaning to see your result appear in the same input field where you entered the raw data, you must click anywhere else on the page:

    Code:
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
    <html>
    <head>
    <title>Format to Dollars and Decimal Cents - Demo</title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <script type="text/javascript">
    function dollarize(tot){
    var orig=tot, count=0
    var tot=tot.toString().replace(/[,\$]/g, '')
    for (var i_tem = 0; i_tem < tot.length; i_tem++){
    count=tot.charAt(i_tem)=='.'? count+1 : count
    if ((isNaN(tot.charAt(i_tem))&&tot.charAt(i_tem)!=='.')||count>1){
    alert('Valid Numbers or Valid Dollar Values only Please')
    return orig;
    }
    }
    tot=tot.indexOf('.')==-1? tot+='.0' : tot.length-tot.indexOf('.')==1? tot+='0' : tot
    tot=tot.split('.')
    tot[2]=''
    count=0
    tot[0]=parseInt(tot[0], 10).toString()
    for (var i_tem = tot[0].length-1 ; i_tem > -1 ; i_tem--){
    if (count&&count%3==0)
    tot[2]+=','
    tot[2]+=tot[0].charAt(i_tem)
    count++
    }
    tot[0]=''
    for (var i_tem = tot[2].length-1 ; i_tem > -1 ; i_tem--)
    tot[0]+=tot[2].charAt(i_tem)
    tot='$'+(tot[0]==''? '0' : tot[0])+'.'+Math.round(Math.abs('.'+tot[1])*100)
    tot=tot.length-tot.indexOf('.')==2? tot+='0' : tot
    return tot;
    }
    </script>
    </head>
    <body>
    Enter Dollar amount below:<br>
    <input type="text" onchange="this.value=dollarize(this.value)">
    </body>
    </html>
    Last edited by jscheuer1; 11-05-2005 at 06:59 AM.
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  5. #5
    Join Date
    Dec 2004
    Location
    UK
    Posts
    2,358
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default

    Quote Originally Posted by jscheuer1
    It ignores the commas that the OP requested but otherwise works very well.
    No, it doesn't. I just assumed that I explained the arguments in that thread (I usually do).

    All are optional strings. The first (c) is the currency symbol, which defaults to none (an empty string). The second (t) is the thousands grouping symbol. This also defaults to none, so the OP will want to pass a comma. The third (d) is the decimal symbol, which defaults to a dot.

    I do have some other code that could be used to more easily parse the resulting strings (including European formats: 1.234,56) back to numbers, but as I recall the regular expression pattern it uses is broken. I didn't check last night, I just decided not to post it.

    I'm wondering how long it will take me to understand what you've done.
    You know I have no problem explaining any part of that post.

    var tot=tot.toString().replace(/[,\$]/g, '')
    The backslash isn't necessary within the character class. A literal carat (^) would need escaping if it was first in the class. A literal closing bracket (]) would need escaping anywhere, as would a backslash itself. A literal hyphen (-) would need escaping if it had pattern characters before and after (for matching 'a', 'z', and '-', an escape is needed in [a-z], but not [-az] or [az-]).

    for (var i_tem = 0; i_tem < tot.length; i_tem++){
    count=tot.charAt(i_tem)=='.'? count+1 : count
    if ((isNaN(tot.charAt(i_tem))&&tot.charAt(i_tem)!=='.')||count>1){
    alert('Valid Numbers or Valid Dollar Values only Please')
    return orig;
    }
    }
    I'd use a regular expression here. For instance, in the isReal method in the other thread. I find them simpler to work with.

    tot[0]=parseInt(tot[0], 10).toString()
    I'm curious about that because I don't believe it does anything. You've already validated the string, so it will only contain digits and a single dot. As you've split on that delimiter, the elements will only contain digits, so the string above should always be the same before and after. Unless I've missed something.

    for (var i_tem = tot[2].length-1 ; i_tem > -1 ; i_tem--)
    tot[0]+=tot[2].charAt(i_tem)
    You could use the reverse method here, instead.

    Mike

  6. #6
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    Mike, I'll look into those delimiter options.

    Quote Originally Posted by Mike
    You know I have no problem explaining any part of that post
    Thanks, it is more fun to work out why code works, like a puzzle. That way I usually remember more of it's methodology. I'm not worried about it though, I know you are always good that way, I was still focusing on getting my version working though. On to your questions as regards that, I too am always willing to explain the workings of my alleged mind:

    This:

    Code:
    var tot=tot.toString().replace(/[,\$]/g, '')
    was condensed from a longer version that did require the escaping the $.

    for (var i_tem = 0; i_tem < tot.length; i_tem++){
    count=tot.charAt(i_tem)=='.'? count+1 : count
    if ((isNaN(tot.charAt(i_tem))&&tot.charAt(i_tem)!=='.')||count>1){
    alert('Valid Numbers or Valid Dollar Values only Please')
    return orig;
    }
    }
    I'd use a regular expression here. For instance, in the isReal method in the other thread. I find them simpler to work with.
    Just what I am more familiar with in this case.

    This was added last:

    Code:
    tot[0]=parseInt(tot[0], 10).toString()
    when I discovered that an initial value of '00.00' would yield '$00.00' when what I was looking for, for that, is '$0.00'


    Code:
    for (var i_tem = tot[2].length-1 ; i_tem > -1 ; i_tem--)
    tot[0]+=tot[2].charAt(i_tem)

    You could use the reverse method here, instead.
    I went right to the reverse method in one of my favorite online resources for scripting methods but, it appeared to me that it only applied to arrays. In the above, I am reversing a string. I thought, "How odd you can reverse an array but not a string", and thought I might be missing something but, just wanted to get it written so, came up with the above method.
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  7. #7
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    OK, I messed around with this a bit more and this incorporates most of Mike's suggestions. I wasn't sure how to use regular expressions in the validation because of the need to ensure that the decimal point appears only once in the input. I also updated it to take care of an error that had crept in when I added the parseInt check, and condensed the code a bit as well (Mike's idea about the reverse method helped with this too):

    Code:
    <script type="text/javascript">
    function dollarize(q){
    var tot=q.toString().replace(/[,$]/g, ''), count=0
    for (var i_tem = 0; i_tem < tot.length; i_tem++){
    count=tot.charAt(i_tem)=='.'? count+1 : count
    if ((isNaN(tot.charAt(i_tem))&&tot.charAt(i_tem)!=='.')||count>1){
    alert('Valid Numbers or Valid Dollar Values only Please')
    return q;
    }
    }
    tot=tot.indexOf('.')==-1? tot+='.0' : tot.length-tot.indexOf('.')==1? tot+='0' : tot
    tot=tot.split('.')
    tot[2]=''
    count=0
    tot[0]=tot[0]==''? '0' : parseInt(tot[0], 10).toString()
    for (i_tem = tot[0].length-1 ; i_tem > -1 ; i_tem--){
    if (count&&count%3==0)
    tot[2]+=','
    tot[2]+=tot[0].charAt(i_tem)
    count++
    }
    tot='$'+tot[2].split('').reverse().join('')+'.'+Math.round(Math.abs('.'+tot[1])*100)
    tot=tot.length-tot.indexOf('.')==2? tot+='0' : tot
    return tot;
    }
    </script>
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  8. #8
    Join Date
    Dec 2004
    Location
    UK
    Posts
    2,358
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default

    Quote Originally Posted by jscheuer1
    [My offer to explain]

    Thanks, it is more fun to work out why code works, like a puzzle. That way I usually remember more of it's methodology.
    I know, which is why I just restated the offer. Besides, I'm all for people learning things for themselves - it's what I did (for the most part).

    This was added last:

    Code:
    tot[0]=parseInt(tot[0], 10).toString()
    when I discovered that an initial value of '00.00' would yield '$00.00' when what I was looking for, for that, is '$0.00'
    Ah, I see. The regular expression I referred to wouldn't allow leading zeros. If I was concerned about it, I'd strip them out of the string at the start before validation:

    Code:
    string.replace(/^0*(\d)/, '$1')
    
    /* Or, to maintain the sign:
     *
     * (/^([+-]?)0*(\d)/, '$1$2')
     */
    Your way could be simplified a bit:

    Code:
    tot[0] = String(+tot[0]);
    I went right to the reverse method in one of my favorite online resources for scripting methods but, it appeared to me that it only applied to arrays.
    I could have sworn there was one, but obviously not. I wouldn't have ever used either to date, in any case.

    Mike

  9. #9
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    Looks like we cross posted again, Mike. Been a while. Anyways, you might want to check over my post from right before yours in this thread, just out of interest. I incorporated some of your ideas, streamlined a bit and found and fixed a problem with parseInt(). Two main things:

    1 ) Found a way to reverse a string using the reverse() method:

    Code:
    string=string.split('').reverse().join('');
    Doesn't work with a true number, so if there is any doubt:

    Code:
    string=string.toString().split('').reverse().join('');
    2 ) I'm at a loss as to how to use a regex to determine if there are none or one and only none or one decimal point(s) in the original value, seems doable, though it might not be as economical, code wise, as my method. I'll leave the determination on processing efficiency up to you.
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  10. #10
    Join Date
    Dec 2004
    Location
    UK
    Posts
    2,358
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default

    Quote Originally Posted by jscheuer1
    I [...] found and fixed a problem with parseInt().
    The parseInt function, applied to an empty string, will return NaN. The unary plus (+) operator - the alternative I suggested - will type-convert an empty string, or a string of white space, to +0.

    I tend to reserve parseInt for situations where I want to convert from bases other than decimal or hexadecimal (as unary + handles both [if the string begins 0x or 0X]), or when the string ends with non-digit characters that can be safely ignored, such as the units in CSS length values.

    1 ) Found a way to reverse a string using the reverse() method:

    Code:
    string=string.split('').reverse().join('');
    Personally, I'd avoid it altogether.

    Doesn't work with a true number, so if there is any doubt:

    Code:
    string=string.toString().split('').reverse().join('');
    Though calling toString method works here, I prefer to use the String constructor function for conversions and allow the interpreter to determine how to perform the operation. This works in all circumstances, whereas an object doesn't necessarily need to have a toString method.

    I'm not saying, "Change it!"; just sharing methodology.

    2 ) I'm at a loss as to how to use a regex to determine if there are none or one and only none or one decimal point(s) in the original value, seems doable, though it might not be as economical, code wise, as my method.
    The simplest regular expression that would match a number - either integer or floating point - is:

    Code:
    /\d+(\.\d+)?/
    This would allow leading zeros, but it would also match any string that contained a number. So, to prevent the latter, one can add assertions that match the beginning and end of a string:

    Code:
    /^\d+(\.\d+)?$/
    The expression would now match a string that contained only a number.

    The regular expression in the other thread is the next evolution, forbidding leading zeros and allowing a sign.

    As for usage, it's as simple as:

    Code:
    if(/^\d+(\.\d+)?$/.test(string)) {
      /* Matches number pattern */
    }
    Mike

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •