JavaScript, Excel, Auto Format Numbers and International Currency

By Robbe D. Morris

Printer Friendly Version

Robbe Morris
Robbe & Melisa Morris
Excel like auto formatting numbers in JavaScript such as currency, numbers with decimal points and places, and disabling decimal points is an important part of web based calculation data entry tables.  The code sample below demonstrates how to handle a wide variety of number formats.  It also lets you integrate internationalization as part of your formatting scheme.
 


 
I opted to approach this is in somewhat of a simplistic manner.  When processing the textbox onBlur(), the value would be stripped of all non-numeric characters, retrieve the country specific decimal and comma character, and apply the formatting.  FormatNumber() is the primary function.  GetDecimalDelimiter() and GetCommaDelimiter() contain characters for three separate countries (I just made up the symbols).  This will enable the developer to implement a wide variety of custom formats.  The developer can also implement custom rounding solutions should it be necessary.  Plus, I think that you'll find this approach makes it easier to convert seemingly improper numeric values during math functions and convert the values back after the math has been completed.
Implementing this in your own pages is easy.  Just put the JavaScript in a separate file and include it in your applicable pages.  Feel free to test out the various number formats below.

Sample Playground
Country 1 ( Comma= , Places = 6 )
Country 2 ( Comma= , Decimal= , Places = 1 )
Country 3 ( Comma= * Decimal= # Places = 2 )
Country 1 ( Comma= , Places = 3 )
Country 2 ( Comma= , Decimal= , Places = 4 )
Country 3 ( Comma= * Decimal=# Places = 5 )

Sample Code
  

<HTML>
<HEAD>

<script language=JavaScript>
  
 function GetDecimalDelimiter(countryCode)
{
 
  switch (countryCode)
  {
    case 3:   
           return '#';
    case 2:   
           return ',';
    default:
           return '.';
  }
}

function GetCommaDelimiter(countryCode)
{
 
  switch (countryCode)
  { 
    case 3:          
           return '*';
    case 2:   
           return ',';
    default:
           return ',';
  }
 
}

function FormatClean(num)
{
     var sVal='';
     var nVal = num.length;
     var sChar='';
     
   try
   {
      for(c=0;c<nVal;c++)
      {
         sChar = num.charAt(c);
         nChar = sChar.charCodeAt(0);
         if ((nChar >=48) && (nChar <=57))  { sVal += num.charAt(c);   }
      }
   }
    catch (exception) { AlertError("Format Clean",exception); }
    return sVal;
}
  

function FormatNumber(num,countryCode,decimalPlaces)
{       

  var minus='';
  var comma='';
  var dec='';
  var preDecimal='';
  var postDecimal='';
  
  try 
  {
   
    decimalPlaces = parseInt(decimalPlaces);
    comma = GetCommaDelimiter(countryCode);
    dec = GetDecimalDelimiter(countryCode);
    
    if (decimalPlaces < 1) { dec = ''; }
    if (num.lastIndexOf("-") == 0) { minus='-'; }
   
    preDecimal = FormatClean(num);
    
    // preDecimal doesn't contain a number at all.
    // Return formatted zero representation.
    
    if (preDecimal.length < 1)
    {
       return minus + FormatEmptyNumber(dec,decimalPlaces);
    }
    
    // preDecimal is 0 or a series of 0's.
    // Return formatted zero representation.
    
    if (parseInt(preDecimal) < 1)
    {
       return minus + FormatEmptyNumber(dec,decimalPlaces);
    }
    
    // predecimal has no numbers to the left.
    // Return formatted zero representation.
    
    if (preDecimal.length == decimalPlaces)
    {
      return minus + '0' + dec + preDecimal;
    }
    
    // predecimal has fewer characters than the
    // specified number of decimal places.
    // Return formatted leading zero representation.
    
    if (preDecimal.length < decimalPlaces)
    {
       if (decimalPlaces == 2)
       {
        return minus + FormatEmptyNumber(dec,decimalPlaces - 1) + preDecimal;
       }
       return minus + FormatEmptyNumber(dec,decimalPlaces - 2) + preDecimal;
    }
    
    // predecimal contains enough characters to
    // qualify to need decimal points rendered.
    // Parse out the pre and post decimal values
    // for future formatting.
    
    if (preDecimal.length > decimalPlaces)
    {
      postDecimal = dec + preDecimal.substring(preDecimal.length - decimalPlaces,
                                               preDecimal.length);
      preDecimal = preDecimal.substring(0,preDecimal.length - decimalPlaces);
    }

    // Place comma oriented delimiter every 3 characters
    // against the numeric represenation of the "left" side
    // of the decimal representation.  When finished, return
    // both the left side comma formatted value together with
    // the right side decimal formatted value.
    
    var regex  = new RegExp('(-?[0-9]+)([0-9]{3})');
 
    while(regex.test(preDecimal))
    {
       preDecimal = preDecimal.replace(regex, '$1' + comma + '$2');
    }
       
  }
  catch (exception) { AlertError("Format Number",exception); }
  return minus + preDecimal + postDecimal;
}

function FormatEmptyNumber(decimalDelimiter,decimalPlaces)
{
    var preDecimal = '0';
    var postDecimal = '';
 
    for(i=0;i<decimalPlaces;i++)
    {
      if (i==0) { postDecimal += decimalDelimiter; }
      postDecimal += '0';
    }
   return preDecimal + postDecimal;
}
  

 function AlertError(methodName,e)
 {
            if (e.description == null) { alert(methodName + " Exception: " + e.message); }
            else {  alert(methodName + " Exception: " + e.description); }
 }

 
 function SetDefaultFormValues()
 {
   document.getElementById('text1').value = FormatNumber(document.getElementById('text1').value,1,6);
   document.getElementById('text2').value = FormatNumber(document.getElementById('text2').value,2,1);
   document.getElementById('text3').value = FormatNumber(document.getElementById('text3').value,3,2);
   document.getElementById('text4').value = FormatNumber(document.getElementById('text4').value,1,3);
   document.getElementById('text5').value = FormatNumber(document.getElementById('text5').value,2,4);
   document.getElementById('text6').value = FormatNumber(document.getElementById('text6').value,3,5);
 }

</script>
 

  </HEAD>
<BODY onload="document.frmSubmit.text1.focus();SetDefaultFormValues();" >
 <form name=frmSubmit id=frmSubmit action="default.htm" method=post>

 <table border="0" align="center" width="80%">

   <tr>
          <td align="left" class="clsBodyText">Country 1 ( Comma= , Places = 6 )</td>
         <td align="left" class="clsBodyText"><input name=text1 type=text value='1019.71' 
              onblur="this.value=FormatNumber(this.value,1,6);" size=30 maxlength=30></td>
   </tr>
   <tr>
          <td align="left" class="clsBodyText">Country 2 ( Comma= , Decimal= , Places = 1 )</td>
         <td align="left" class="clsBodyText"><input name=text2 type=text value='1019.71'
           onblur="this.value=FormatNumber(this.value,2,1);" size=30 maxlength=30></td>
   </tr>
   <tr>
          <td align="left" class="clsBodyText">Country 3 ( Comma= * Decimal= # Places = 2 )</td>
         <td align="left" class="clsBodyText"><input name=text3 type=text value='1019.71' 
             onblur="this.value=FormatNumber(this.value,3,2);" size=30 maxlength=30></td>
   </tr>

   <tr>
          <td align="left" class="clsBodyText">Country 1 ( Comma= , Places = 3 )</td>
         <td align="left" class="clsBodyText"><input name=text4 type=text value='1019.71'
              onblur="this.value=FormatNumber(this.value,1,3);" size=30 maxlength=30></td>
   </tr>
   <tr>
          <td align="left" class="clsBodyText">Country 2 ( Comma= , Decimal= , Places = 4  )</td>
         <td align="left" class="clsBodyText"><input name=text5 type=text value='1019.71'
          onblur="this.value=FormatNumber(this.value,2,4);" size=30 maxlength=30></td>
   </tr>
   <tr>
          <td align="left" class="clsBodyText">Country 3 ( Comma= * Decimal=# Places = 5 )</td>
         <td align="left" class="clsBodyText"><input name=text6 type=text value='1019.71' 
             onblur="this.value=FormatNumber(this.value,3,5);" size=30 maxlength=30></td>
   </tr>
 
 </table>
 
</form>
</BODY>
</HTML>

	    

Robbe has been a Microsoft MVP in C# since 2004.  He is also the co-founder of NullSkull.com which provides .NET articles, book reviews, software reviews, and software download and purchase advice.