The jQuery JavaScript library offers some quick and dirty solutions to many problems. I was perusing a jQuery email list when I ran across a simple problem that a beginner JavaScript coder like me could solve. I'll simplify it a little here to focus this article.

Basically, the poster wanted to add form fields to a table, but he wanted to increment a field counter in the HTML and in the id and name tags. Just to make it a little more difficult, the field numbers needed to be padded with leading zeros.

Adding the table rows is trivial in jQuery and it turns out that leading zeros are pretty easy too. I like the "everything is an object" approach to JavaScript. You can extend even the built-in objects including the String object. Let's tackle that first.

The String object does not have a built-in method of repeating characters and a quick search on the Internet found an efficient solution. We need this to pad the leading zeros. You may want to look up how prototype works, but this is pretty basic JavaScript, so I'll skip the explanation of how it works.

  1. // Add repeat method to String object
  2. String.prototype.repeat = function(n){
  3.     return new Array(n + 1).join(this);
  4. };

We can now do something like this: '0'.repeat(3) to get a string of three zeros ("000"). Next, we can write a short padding routine. I like to think into the future when writing code. Will I need something like this again? Can I make it dynamic? Here's what I came up with.

  1. // Add leading_zeros
  2. var leading_zeros = function(n, total_digits){
  3.     n = n.toString();
  4.     return '0'.repeat(total_digits - n.length) + n;
  5. };

To make this work with jQuery, I like to add it as a jQuery plug in. That's a fancy way of saying that I will add a method to the jQuery object to allow padding. I don't strictly have to do it this way, but I like showing off and I think it makes for cleaner, more usable code. The jQuery Plug In Manual reveals that we should start a new Plug In with this block of code.

  1. (function(){})();

It is not obvious that this function will run autmatically. I couldn't easily find that in many JavaScript reference on line. Next we add some jQuery stuff to this code block. This allows us to safely use the $ inside the block without screwing with other libraries which may be running.

  1. (function($){})(jQuery);

There's one more thing in there I would like to point out. It was not obvious to me when I first looked at this block and it may confuse some readers. According to most resources I found on the web, the $ is not a legal character in a JavaScript variable name.

After some investigation, I found an EcmaScript specification which stated that the $ character is valid as a first character in a variable name. And since JavaScript variables can have just one character, $ is a valid variable name. It is also the name the library author chose to use for the jQuery object.

  1. (function($) {
  3.     // Add repeat method to String object
  4.     String.prototype.repeat = function(n){
  5.         return new Array(n + 1).join(this);
  6.     };
  8.     // Add leading_zeros method to jQuery
  9.     $.leading_zeros = function(n, total_digits){
  10.         n = n.toString();
  11.         return '0'.repeat(total_digits - n.length) + n;
  12.     };
  14. })(jQuery);

We can now use $.leading_zeros(1, 3) to produce a padded string ("001"). Now we need a counter. This will take a static variable. A static variable holds it's contents between calls. In JavaScript, we just need to declare the variable outside the function and it will act as a static variable.

  1. // initialize the counter
  2. var counter = 0;
  4. var count = function(){
  5.     return ++counter;
  6. };
  8. alert( count() ); // 1
  9. alert( count() ); // 2
  10. alert( count() ); // 3

Because of the way scope works, the value of the variable counter is saved between calls to the subroutine count() and we count up in the alerts. Let's wrap this up in the document ready portion of this jQuery application.

  1. $(document).ready(function(){
  3.     // initialize the counter
  4.     var counter = 0;
  6.     $('#fields-button').click(function(){
  8.         // increment and pad the counter
  9.         var padded_counter = $.leading_zeros(++counter, 3);
  11.         // create the new field
  12.         var extrafield = '<tr><td>List Item ' + padded_counter + '</td><td>';
  13.         extrafield += '<input type="text" name="' + padded_counter + '"'
  14.         extrafield += ' id="' + padded_counter + '"></td></tr>'
  16.         // add the new field to the table
  17.         $('#fields').append(extrafield);
  18.     });
  19. });

Putting it all together we get this.

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "">
  2.     <title>Foo</title>
  3.     <script type="text/javascript" src="/site/code/jquery-1.2.2.pack.js"></script>
  4.     <script type="text/javascript">
  6.         (function($) {
  8.             // Add repeat method to String object
  9.             String.prototype.repeat = function(n){
  10.                 return new Array(n + 1).join(this);
  11.             };
  13.             // Add leading_zeros method to jQuery
  14.             $.leading_zeros = function(n, total_digits){
  15.                 n = n.toString();
  16.                 return '0'.repeat(total_digits - n.length) + n;
  17.             };
  19.         })(jQuery);
  21.         $(document).ready(function(){
  23.             // initialize the counter
  24.             var counter = 0;
  26.             $('#fields-button').click(function(){
  28.                 // increment and pad the counter
  29.                 var padded_counter = $.leading_zeros(++counter, 3);
  31.                 // create the new field
  32.                 var extrafield = '<tr><td>List Item ' + padded_counter + '</td><td>';
  33.                 extrafield += '<input type="text" name="' + padded_counter + '"></td></tr>';
  35.                 // add the new field to the table
  36.                 $('#fields').append(extrafield);
  37.             });
  38.         });
  40.     </script>
  41. </head>
  42.     <button id="fields-button">Add Field</button>
  43.     <form action="" method="get">
  44.     <table id="fields"></table>
  45. </form>
  46. </body>
  47. </html>