Before concluding the chapter, let’s present one final example of how intelligence can be added to a Web form to make it dynamic. As we have seen throughout the chapter, it is possible to both read and write form field values; thus, besides checking data and improving form usage, we should be able to use JavaScript to subtotal orders, calculate shipping values, and fill in parts of the form dynamically. The following example shows a simple form that adds up the number of items entered and calculates a subtotal, tax rate, shipping cost, and grand total. A rendering of the example is shown in Figure 14-4.
<<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">> <<html>> <<head>> <<title>>Dynamic Form Demo<</title>> <<meta http-equiv="content-type" content="text/html; charset=utf-8" />> <<script type="text/javascript">> <<!-- // Set up form variables and constants var widgetCost = 1.50; var gadgetCost = 2.70; var thingieCost = 1.25; var taxRate = 0.075; var shippingCost = 0; function isNumberInput(field, event) { var key, keyChar; if (window.event) key = window.event.keyCode; else if (event) key = event.which; else return true; // Check for special characters like backspace if (key == null || key == 0 || key == 8 || key == 13 || key == 27) return true; // Check to see if it.s a number keyChar = String.fromCharCode(key); if (/\d/.test(keyChar)) { window.status = ""; return true; } else { window.status = "Field accepts numbers only."; return false; } } function format(value) { // Format to have only two decimal digits var temp = Math.round(value * 100); temp = temp / 100; return temp; } function calc() { with (document.myform) { widgettotal.value = format(widgets.value * widgetCost); gadgettotal.value = format(gadgets.value * gadgetCost); thingietotal.value = format(thingies.value * thingieCost); subtotal.value = format(parseFloat(widgettotal.value) + parseFloat(gadgettotal.value) + parseFloat(thingietotal.value)); tax.value = format(subtotal.value * taxRate); for (i=0; i << shipping.length; i++) if (shipping[i].checked) shippingcost = parseFloat(shipping[i].value); grandtotal.value = format(parseFloat(subtotal.value) + parseFloat(tax.value) + shippingcost); } } //-->> <</script>> <</head>> <<body>> <<form id="myform" name="myform" action="#" method="get">> Widgets: <<input type="text" name="widgets" id="widgets" size="2" value="0" onchange="calc();" onkeypress="return isNumberInput(this, event);" />> @ 1.50 each <<input type="text" id="widgettotal" name="widgettotal" size="5" readonly="readonly" />> <<br />> Gadgets: <<input type="text" name="gadgets" id="gadgets" size="2" value="0" onchange="calc();" onkeypress="return isNumberInput(this, event);" />> @ 2.70 each <<input type="text" id="gadgettotal" name="gadgettotal" size="5" readonly="readonly" />> <<br />> Thingies: <<input type="text" name="thingies" id="thingies" size="2" value="0" onchange="calc();" onkeypress="return isNumberInput(this, event);" />> @ 1.25 each <<input type="text" id="thingietotal" name="thingietotal" size="5" readonly="readonly" />> <<br />><<br />><<br />> <<em>>Subtotal:<</em>> <<input type="text" id="subtotal" name="subtotal" size="8" value="0" readonly="readonly" />> <<br />><<br />><<br />> <<em>>Tax:<</em>> <<input type="text" id="tax" name="tax" size="5" value="0" readonly="readonly" />> <<br />><<br />><<br />> <<em>>Shipping:<</em>> Next day: <<input type="radio" value="12.00" name="shipping" id="shipping" checked="true" onclick="calc();" />> 2-day: <<input type="radio" value="7.00" name="shipping" id="shipping" onclick="calc();" />> Standard: <<input type="radio" value="3.00" name="shipping" id="shipping" onclick="calc();" />> <<br />><<br />><<br />> <<strong>>Grand Total:<</strong>> <<input type="text" id="grandtotal" name="grandtotal" size="8" readonly="readonly" />> <</form>> <</body>> <</html>>
Note that the previous example uses field masking to avoid excessive checking of form contents and liberal use of the readonly attribute to keep users from thinking they can modify calculated fields. Also note that, because of JavaScript’s relatively poor numeric formatting, we added in a rudimentary formatting function. Given this basic example, you should see how it is possible to add calculators or other more dynamic form applications to your site.
Note |
As we mentioned in the “Validation Best Practices” section, relying on client-side JavaScript to calculate things like sales tax and purchase cost is not a good idea. Anyone can turn off JavaScript, modify the form to indicate 100 widgets at a cost of one penny each, and then submit. Scripts like the one in our previous example should be used only as a convenience to users, that is, to let them see about how much they’ll be spending before they submit the transaction to the server. |