Build Your Own Counter Widgets Using JavaScript and HTML
Building forms can be repetitive work. Often, particular form elements appear consistently across a wide range of forms. These elements lend themselves to creation as components that can be re-used in different forms applications.
One such recurring requirement of forms is the numeric field. Many forms include at least one field that can accept numeric values that occur within a certain range and are rounded to whole numbers (i.e. no decimals are allowed).
Rich-client applications have such a widget — a text field followed by "up" and "down" arrows that allow users to increase or decrease the field’s value. VB.NET calls this widget NumericUpDown.
To provide this functionality in plain HTML, we could use a drop-down list that contained all the possible values as options. This solution has several drawbacks, though:
- If you need the user to choose from a wide range of numbers, the drop-down list can become very long. Users may have to scroll through the list and spend a lot of time to reach the value they want.
- You need a huge amount of markup to generate a drop-down.
A better option is to allow users to enter the value into a simple text field, and validate their entries on the back-end.
We need to use back-end validation, as we cannot rely on the availability of JavaScript on the users’ systems. However, we can use JavaScript to avoid frustrating page reloads, and to turn the simple text field into a "counter" widget.
The field in the demonstration page is enhanced by a script that creates links to increase or decrease the field value when Javascript is available. For access to all the code presented in this article, download the code archive here.
How It Works
To achieve the desired functionality, all we need to do is to embed the file createcounter.js in our HTML document:
<script type="text/javascript" src="createcounter.js"></script>
We also need to add a special ID to each text field that we want to become a counter:
<input type="text" size="3" name="passengers_ctr_1_12" id="passengers_ctr_1_12" value="1" />
(The name attribute is kept in the code to ensure backward compatibility.)
The syntax of the ID is as follows:
(any name)_ctr_(minimum value)_(maximum value)
foo_ctr_0_10
Allows integer values between 0 and 10 for foo
bar_ctr_-10_10
Allows integer values between -10 and 10 for bar
baz_ctr_1_999
Allows integer values between 1 and 999 for baz
Instead of the ID, we could use a class
name or a
bespoke attribute with a proper namespace. Using the ID, however, enables us to replicate this same validation on the back end, for example, in PHP.
Some developers might frown upon this mixing of markup and business logic, but it saves us from needing to replicate the rules from the JavaScript code in the back end script.
The JavaScript automatically:
- checks that the entry is a number, an integer, and within the specified range
- checks the value of the counter element when the page is loaded
- checks and increases the value when the increase link is clicked
- checks and decreases the value when the decrease link is clicked
- checks the value once the user has entered text and left the field
If the entry either is not a number, or is below the minimum value allowed, the script sets the value to the minimum. If the entry is above the maximum, the script sets it to the maximum.
Customise the Widget
The class
counterlink is applied to the links generated through this solution. The links can therefore be customized via CSS. To customize the class name and displayed link text, set the variables as follows:
var linkclass='counterlink';
var addtext='+';
var subtext='-';
var addbefore=true;
The variable
addbefore defines the location of the decreasing link. A value of
true applies the link before the text field. A value of
false defines it after the text field, next to the increasing link.
Drawbacks of the Solution
This is as far as HTML, CSS and JavaScript can take us while remaining mouse-independent. Real counter widgets allow users to increase and decrease values via the cursor keys, and accelerate the scrolling speed the longer the user keeps either arrow button depressed.
There may be a solution that allows this functionality in certain browser environments, but it is doubtful that it can be made to work across all modern browsers.