3. Intelligent Forms

Whether you want to book a flight, take care of your online banking, or enter a search term in Google, without forms, none of these services would be usable. Most of the elements for interactive forms have remained unchanged since HTML 2.0 arrived in 1995. On one hand this indicates that Tim Berners-Lee’s design showed great foresight; on the other hand there is now a huge need to catch up. The HTML5 specification devotes a large section to the topic of forms and will greatly facilitate any web designer’s work.

Even though browser support is not yet overwhelming at the time of this writing (so far, it’s only offered by Opera and the developer release of Google Chrome), the backward compatible syntax means that we can safely use the new form elements now.

3.1 New Input Types

The HTML5 specification enhances the input element by allowing several more values for the type attribute. The new types, for example, date, color, and range, enable browser manufacturers to make user-friendly input elements available and also make it possible for the browser to ensure that the input is of the desired type. If a browser does not recognize the type of the input element, it will fall back on type=text and display a text field, which is useful in any case. Even older browsers show this behavior, so there is nothing to stop us from using the new types right away.

The types for date and time will probably be the most useful. Currently, there are countless different versions of more or less successful JavaScript calendars available on the Internet. Entering a date comfortably, be it for booking a flight or a hotel room, or registering for a conference, is a problem that until now required manual work. Of course, JavaScript libraries, such as jQuery, offer ready-made calendars, but this function should really be supported by the browser directly.

At the time of this writing, there is only one desktop browser that includes a graphic input element for entering the date: Opera. In Figure 3.1 you can see the open calendar that will be displayed if you click on an input element with the type date. But let’s tackle things in order: Table 3.1 provides an overview of the new types; then you can see what they look like in the Opera browser in Figure 3.1.

Figure 3.1 Opera is already far ahead regarding implementation of new form input types

image

Table 3.1 New Input Types in HTML5

image

3.1.1 The Input Types “tel” and “search”

tel and search are not significantly different from normal text fields. Both can contain character chains without line breaks. Even telephone numbers are not limited to numbers, because phone numbers often contain brackets or the plus symbol. For tel, the browser could offer suggestions from the local address book, a situation that is particularly useful with cell phones. The search type was introduced to allow the browser to make the search input consistent with the layout of the relevant platform. Mac OS X users, for example, are used to seeing search fields with rounded corners.

3.1.2 The Input Types “url” and “email”

In addition to suggesting options, the browser can also check the syntax for url and email. Because there are concrete rules for e-mail addresses and Internet addresses in the form of URLs, the browser can already provide feedback on possible mistakes during input (more on this topic in section 3.4, Client-side Form Validation).

3.1.3 Date and Time with “datetime”, “date”, “month”, “week”, “time”, and “datetime-local”

Let’s take a closer look at the date and time formats. datetime contains date and time information; the time zone is always set to UTC. The specification states that the browser can allow the user to select another time zone, but the value of the input element has to be converted to UTC. The rules for time information in the datetime attribute of the time element, which we discussed in section 2.7.2, The “time” Element, apply here as well—with the only exception that the string always has to end in a Z, the identifier of UTC.

With date and month, the time and time zone are omitted. As defined in the specification, the date must be a valid day within the selected month, also taking into account leap years. Year, month, and day must be separated by a minus character; the year has to be at least four digits long and greater than 0. So dates before Christ (B.C.) cannot be represented in HTML5, in contrast to the somewhat more extensive international standard ISO 8601.

The type week is represented as a week in a year, and it is mandatory that the week be preceded by the year. Year and week are once again separated by a minus character. To ensure that there is no confusion with month, the week must be preceded by the character W.

datetime-local works the same way as the already described datetime; the only difference is that there is no timezone specified.

Opera uses a calendar window for selecting the date; the time can be entered manually or changed via arrow keys (refer to Figure 3.1).

3.1.4 The Input Types “number” and “range”

The types number and range require input that can be converted to a numerical value; the notation of floating-point numbers (for example, 2.99792458E8) is valid. Regarding the type range, the specification states that the exact value is not relevant; this type indicates a range of numbers, not an exact number, and the user can easily enter it with a slider bar. Both Opera and WebKit-based browsers, such as Safari or Google Chrome, use a slider bar to represent this type (refer to Figure 3.1 and see Figure 3.2).

Figure 3.2 The input type “range” in Safari

image

3.1.5 The Input Type “color”

Once again the developers of Opera lead the way by being the first to program a graphical input option for the color element. As you can see in Figure 3.1, Opera (version 11 and later) offers a rectangular field with a choice of frequently used colors. You can also bring up a color picker along the lines of those you see in image-editing programs. Sadly, this input element is still not implemented in the other browsers.

The value of the input element must contain the 8-bit RGB values in hexadecimal notation preceded by a # character. The color blue, for example, would be written as #0000ff.

3.1.6 The New Input Types in Action

Enough with the theory: Our first example shows you the new elements, one below the other. Because that’s not very challenging, we will also test each element’s function. The trick is that the browser will set the type of an unknown element to text, and we can then evaluate those properties in JavaScript:

<script>
  window.onload = function() {
    inputs = document.getElementsByTagName("input");
    for (var i=0; i<inputs.length; i++) {
      if (inputs[i].type == "text") {
        inputs[i].value = "not available";
      }
    }
  }
 </script>

As soon as the web page has finished loading, a loop runs over all input elements to analyze their type attributes. If the type attribute corresponds to the standard type text, its value is set to not available. The HTML code for the new input elements looks like this:

<fieldset>
  <legend>New input types</legend>
    <p><label for=tel>tel</label>
 <input type=tel id=tel name=tel>
    <p><label for=search>search</label>
 <input type=search id=search name=search>
    <p><label for=url>url</label>
 <input type=url id=url name=url>
    <p><label for=email>email</label>
 ...

In Figure 3.3 you can see what the result of this test looks like on an Android cell phone. The system’s WebKit-based browser (left) pretends to know the types tel, search, url, and email but does not really help when it comes to entering the telephone number via the keyboard (center). Opera Mobile in version 10.1 beta (right) supports url and email, plus the date and time types.

Figure 3.3 Support of new form input types on an Android 2.1 phone with browsers WebKit (left, center) and Opera (right)

image

That is a rather disappointing result for the otherwise so modern Android browser. Results look slightly better on the iPhone: At least the smartphone adapts the software keyboard, displaying a numeric keyboard when you try to enter a phone number and adding the @ character on the keyboard for the input type email.

This test works even better with BlackBerry, the operating system of the popular line of smartphones produced by the Canadian manufacturer Research in Motion (RIM). As you can see in Figure 3.4, the BlackBerry supports both tel and number plus date types, and the latter in particular are represented in very attractive graphics. Under the hood we find WebKit at work: The software was expanded to include these functions.

Figure 3.4 The new input types on a BlackBerry smartphone (BlackBerry 9800 simulator)

image

3.2 Useful Attributes for Forms

Apart from new elements and many new types for the input element, HTML5 also offers several new attributes for form elements.

3.2.1 Focusing with “autofocus”

Years ago, Google surprised many users with a simple trick that made searching much more convenient: When the page was loaded, the cursor was automatically positioned in the search field. The user was able to enter the search term directly without having to first activate the input box by clicking with the mouse. Previously, this was done with a short snippet of JavaScript; in HTML5 you can now do it with the autofocus attribute:

<input type=search name=query autofocus>

As with all boolean attributes, you can write this attribute as autofocus="autofocus" (see Chapter 2, section 2.7.2, The “time” Element). The specification states that only one element in a web page can contain the autofocus attribute.

Older browsers do not have a problem with autofocus, because they simply ignore the unknown attribute. Of course, you only get the benefit of user friendliness with new browsers.

3.2.2 Placeholder Text with “placeholder”

Usability of HTML forms can be further improved with the new placeholder attribute:

<p><label for=email>Your e-mail address:</label>
<input type=email name=email id=email
  placeholder="[email protected]">
<p><label for=birthday>Your date of birth</label>
<input type=date name=birthday id=birthday
  placeholder="1978-11-24">

The value of placeholder can give the user a quick hint about how to fill in the field, but it should not be used as an alternative to the label element. It is particularly useful for fields where a certain data entry format is expected. The browser displays the hint text within an inactive input field. As soon as the field is activated and is focused, the text is no longer displayed (see Figure 3.5).

Figure 3.5 The “placeholder” attribute in Google Chrome

image

3.2.3 Compulsory Fields with “required”

required is a boolean attribute, and its name already says everything about its function: A form element that this attribute is assigned to must be filled in. If a required field remains blank when the form is sent, it does not fulfill the requirements and the browser must react accordingly. You will find more information on this in section 3.4, Client-side Form Validation.

3.2.4 Even More Attributes for the “input” Element

The input element has not only been enhanced with new types (section 3.1, New Input Types), but also with new attributes that enable easier handling of forms (see Table 3.2).

Table 3.2 New Attributes for the “input” Element

image

We will come across the list attribute again in section 3.3.3, Lists of Options with “datalist”. It refers to the datalist element, which offers possible entries as suggestions.

min, max, and step are not only suitable for numeric fields, but these attributes can also be used for entering the date and time:

<p><label for=minMax>Decimal number between 0 and 1:</label>
<input type=number name=minMax id=minMax
  min=0 max=1 step=0.1>
<p><label for=minMaxDate>Date in week steps:</label>
<input type=date name=minMaxDate id=minMaxDate
  min=2010-08-01 max=2010-11-11 step=7>
<p><label for=minMaxTime>Time in hour steps:</label>
<input type=time name=minMaxTime id=minMaxTime
  min=14:30 max=19:30 step=3600>

In browsers that support the input type number, the first input element (id=minMax) is increased each time by a value of 0.1. This works by clicking the arrow keys at the end of the text field or by pressing the arrow keys on the keyboard. The element with the ID minMaxDate jumps forward seven days each time. Opera only displays those days in the calendar as active that correspond to the week cycle. For setting this element, Google Chrome offers the same navigation as with the input type number: two arrow keys that set the date forward or backward seven days. In the third input element in this example, the step size is set to 3600; this causes the time to be set one hour forward or one hour backward. Although the specification states that the input elements for time usually work in minutes, both Opera and Google Chrome interpret this data as seconds.

We are all familiar with multiple selection from copying files; now this option exists for browsers as well. If you wanted to load several files on a website at once, you previously had to provide an input field for each file. The multiple attribute allows for the marking of several files in the file dialog. The multiple option was always intended for the select element; using it for input fields of the type email is new. But as yet (at the time of this writing), none of the commonly used desktop browsers can implement this function for email types.

Modern browsers have a function that allows them to save form data to help the user fill in forms when the form is revisited. This prefilling can be very useful but would be undesirable for security-sensitive input fields (the specification mentions the activation codes for nuclear weapons as an example). The autocomplete attribute was introduced to allow web developers to govern this behavior. If an element has the attribute autocomplete="off" assigned to it, that means the information to be entered is confidential and should not be saved in the browser. If the form element does not state if autocomplete should be switched on or off, the default setting is to display suggestions. The autocomplete attribute can also be applied to the whole form by assigning it to the form element.

The new pattern attribute allows for very flexible input verification. You can specify a regular expression against which the form field will be checked for a match. Regular expressions are very powerful but unfortunately not a very easy method of parsing strings. Imagine you are looking for a character string starting with an uppercase character followed by any number of lowercase letters or numbers and ending in .txt. Finding it is no problem at all with a regexp (short for regular expression):

[A-Z]{1}[a-z,0-9]+.txt


Note

image

An introduction to regular expressions would be far beyond the scope of this chapter, so let’s assume for now that you have basic knowledge of regular expressions when you read the following section. If you are looking for a brief online introduction to regular expressions, Wikipedia is a good starting point: Browse to http://en.wikipedia.org/wiki/Regular_expression. The website http://www.regexe.com gives you the chance to try regular expressions online.


When using regular expressions with the pattern attribute you need to remember that the search pattern always has to apply to the field’s entire content. The specification also suggests using the title attribute to give the user a hint regarding the input format. Opera and Google Chrome display this kind of information as a tool tip as soon as the mouse pointer hovers over the field. After all this theory, here is a brief example:

<p><label for=pattern>Your nickname:</label>
 <input type=text pattern="[a-z]{3,32}"
  placeholder=""johnsmith" name=pattern id=pattern
  title="Only lower case, please; min. 3, max. 32!">

The guideline for the pattern attribute specifies that the character string can only contain characters between a and z (in lowercase,[a-z]) and that there are at least 3 and at most 32 characters. Special characters or umlauts are not allowed, which can be useful for a user name as in the preceding example. If you want to include certain special characters, for example, the umlauts in the German language, you need to include them in the group: [a-zäöüß]. In section 3.4, Client-side Form Validation, you can find out what happens if the validation fails.

3.3 New Elements

In addition to the new input types and the new attributes mentioned earlier, the specification also includes new elements for forms. We will discuss these in the next section. The elements meter and progress create graphical objects that previously could only be achieved with more or less complicated tricks. Suggestions for text input are offered by datalist, and output provides a placeholder for the results of calculations. The keygen element has been circulating through the World Wide Web for a long time but has only reached standardization with HTML5.

3.3.1 Displaying Measurements with “meter”

The meter element is used to graphically represent a scalar measurement within a known range. Think, for example, of the fuel gauge in your car: The needle shows the current level of fuel in your tank as somewhere between 0 and 100 percent. Previously, such graphic representations were usually coded in HTML with nested div elements, a rather inelegant solution for which the div element was probably not intended. A status display can also be displayed graphically, as a picture, through free web services, such as the Google Chart API. You can see all of these options in the example that follows.

Using the meter element is very simple: You set the desired value via the value attribute; all other attributes are optional. If you do not set a min and max value, the browser will use 0 and 1 for these attributes. So, the following meter element shows a half-full element:

<meter value=0.5></meter>

Apart from value, min, and max are also the attributes low, high, and optimum—values that the browser can incorporate into the display. Google Chrome (at the time of this writing, the only browser apart from Opera that is able to represent the meter element), for example, displays the normally green bar in yellow if the optimum value is exceeded.

In the following example you can see a graphic representation, showing the percentage of the current year that has already passed. The website presents a visualization of the output in four different ways: as text with a value in percent, using the new meter element, via nested div elements, and as graphics produced by the online service of Google’s Chart API. You can see the result in Figure 3.6.

Figure 3.6 The “meter” element and similar options for representing a state

image

The HTML code for this example contains the still empty elements, which are filled via JavaScript:

<h2>Text</h2>
<p><output id=op></output>
  % of the year has passed.</p>
<h2>The new <span class=tt>meter</span> element</h2>
<meter value=0 id=m></meter>
<h2>Nested <span class=tt>div</span> elements</h2>
<div id=outer style="background:lightgray;width:150px;" >
<div id=innerDIV>&nbsp;</div></div>
<h2>Google Chart API</h2>
<img id=google src="">
<p id=googleSrc class=tt></p>

For the text output, we use the output element introduced in section 3.3.5, Calculations with “output”. But first the current date is generated in JavaScript, and the meter element is initialized:

var today = new Date();
var m = document.getElementById("m");
m.min = new Date(today.getFullYear(), 0, 1);
m.max = new Date(today.getFullYear(), 11, 31);
// m.optimum = m.min-m.max/2;
m.value = today;

The variable today contains the number of milliseconds since the start of the UNIX epoch (on 1.1.1970). To make sure our meter element gets a sensible scale, we set the min value to January 1 of the current year and the max value accordingly to December 31. The value of the meter element is set in the last line of the listing; now the graphical representation is complete. If you activate the optimum value (in this case the middle of the year), which we left out, you will see the display change depending on whether you call the script in the first or second half of the year. The new element is wonderfully simple to use.

Let’s now move on to the other elements on our HTML web page. We want to assign the percentage of days passed to the output element tagged with the ID op. With Math.round(), we round up the percentage to the nearest number before the comma, which is plenty accurate enough for our example:

var op = document.getElementById("op");
op.value =
  Math.round(100/(m.max-m.min)*(m.value-m.min));

var innerDIV = document.getElementById("innerDIV");
innerDIV.style.width=op.value+"%";
innerDIV.style.background = "green";

The rest of our example has nothing to do with new HTML5 techniques, but we still want to explain it for the sake of completeness. The nested div elements should also be filled with the percentage value. The idea behind this is simple: A first div area is defined in HTML with a fixed width (here, 150px). Nested into this element, another div element is displayed as filled with a green background color along the width of the calculated percentage value—a simple yet very effective trick. To round things off, we also want to include the Google Chart API. To use the online service, you have to specify the chart size (chs, in our case 200×125 pixels), the chart type (cht, here, gom, Google-O-Meter), and the chart data (chd, here, the percentage value op.value):

  var google = document.getElementById("google");
  google.src =
"http://chart.apis.google.com/chart?chs=200x125&cht=gom&chd=t:"+op.
value;
  var gSrc = document.getElementById("googleSrc");
  gSrc.innerHTML = google.src;

3.3.2 Displaying the Progress of a Task with “progress”

progress works in a similar way as the meter element discussed previously except that it represents the completion progress of a task. Such tasks could, for example, be file uploads by the user or downloads of external libraries required by an application.

To give you a quick example, we do not really want to upload any files or download a lot of data; it is sufficient to set ourselves a task and fulfill it 100 percent. Our following example defines ten input elements of the type checkbox, and as soon as they are all activated, we want the progress bar to show 100 %:

<h1>Please activate all the checkboxes</h1>
<form method=get>
  <input type=checkbox onchange=updateProgress()>
  <input type=checkbox onchange=updateProgress()>
<!-- and 8 more -->
  <p>
  Progress: <progress value=0 max=10 id=pb></progress>
</form>

The progress element is initialized with a value of 0 and a maximum value of 10. As soon as an input element is activated, it calls the function updateProgress(), which looks like this:

function updateProgress() {
  var pb = document.getElementById("pb");
  var ip = document.getElementsByTagName("input");
  var cnt = 0;
  for(var i=0; i<ip.length; i++) {
    if (ip[i].checked == true) {
      cnt++;
    }
  }
  pb.value = cnt;
}

The variable ip contains a NodeList with all input elements. Each of these elements is tested in the for loop for its condition. If it is activated (checked == true), the counter variable cnt increases by 1. To finish, the value of the progress element is set to the value of the counter variable.

3.3.3 Lists of Options with “datalist”

One long-awaited new function for forms is a drop-down menu to which you can add your own entries. Because the well-known select element is limited to the values specified as option elements, web developers used to come up with various JavaScript tricks to add expandable selection lists to text fields.

The HTML5 specification now has a very elegant solution to this problem. The new datalist element was defined to function as a container for the already familiar option element. Now we can assign to each input element a datalist element that displays the selection options when needed. Browsers that do not support the datalist element will only display the empty text field.

Listing 3.1 shows the use of the new element. The input element is defined by the type text, and the attribute list refers to the id of the datalist element (in this case, homepages). When the page is loaded, the autofocus attribute positions the cursor automatically inside the text field (see section 3.2.1, Focusing with “autofocus”) and ensures, at least with the Opera browser, that the selection list appears (see Figure 3.7).

Figure 3.7 Opera, representing a “datalist” element

image

For the option elements within the datalist, you just need to fill the value attribute. Further attributes and a text node are possible but not required for this use. If the user clicks the Submit button, the content of the text field is prefixed with the character string http:// and the browser is redirected to the resulting URL (window.location):

Listing 3.1 The “datalist” element filled with Internet addresses


<form>
  <p>
  <label for=url>Goto</label>
  http://<input type=text id=url name=homepage
                 list=hompages autofocus>
  <datalist id=hompages>
    <option value=www.google.com>
    <option value=html5.komplett.cc/welcome>
    <option value=slashdot.org>
    <option value=wired.com>
  </datalist>
  <input type=submit
    onclick="window.location =
    'http://'+document.getElementById('url').value;
    return false;" >
</form>


If you want to equip older browsers with a selection list without duplicating the HTML code, you can fall back on the following trick. Because browsers supporting the datalist element ignore an enclosed select element, they display the new HTML5 select element. Older browsers, however, display a selection list for the text field with predefined links, which will be inserted into the text field when the selection is changed.

As you can see in Listing 3.2, we need to add a text node to the option elements because the “old” select element does not show the content of the value attribute but instead shows the text:

Listing 3.2 A “datalist” with the fallback for older browsers


<datalist id=hompages>
<select name=homepage
  onchange="document.getElementById('url').value =
    document.forms[0].homepage[1].value" >
  <option value=www.google.com>www.google.com
  <option
  value=html5.komplett.cc/welcome>html5.komplett.cc/welcome
  <option value=slashdot.org>slashdot.org
  <option value=wired.com>wired.com
</select>
</datalist>


The onchange event within the select element inserts the current text of the selection menu into the text box (see Figure 3.8).

Figure 3.8 A combination of “input” and “select” elements as fallback for older browsers (here, Internet Explorer 8)

image

3.3.4 Cryptographic Keys with “keygen”

The keygen element has a long history in the Mozilla Firefox browser (included since version 1.0), but Microsoft still expressed great concern regarding the implementation in HTML5. keygen is used to generate cryptographic keys, which sounds complicated, and unfortunately, it is just as complicated as it sounds.

Simply put, the idea behind this element is this: The browser creates a pair of keys, one a public key and the other a private key. The public key is sent off with the other form data and is then available to the server application, whereas the private key remains saved in the browser. After this exchange of keys, the server and browser can communicate in encryption without SSL certificates. This sounds like a practical solution for those pesky self-signed certificates, which browsers keep complaining about, but sadly it is not, because the identity of the server can only be verified through a certificate that has been signed by a trustworthy authority, the Certificate Authority (CA).

So if keygen cannot replace SSL, what should the new element be used for? As explained in the Mozilla documentation, the keygen element helps create a certificate that the server can sign (signed certificate). To make this step totally secure, it is usually necessary for the applicant to appear personally before the authority. Because the issuing of signed certificates is a task for experts, we will briefly describe this element and its attributes.

The following short HTML document creates a keygen button:

<!DOCTYPE html>
  <meta charset="utf-8">
  <title>keygen Demo</title>
  <form method=post action=submit.html>
    <keygen id=kg challenge=hereismychallenge name=kg>
    <input type=submit>
  </form>

In addition to the familiar attributes, such as autofocus, disabled, name, and form, the keygen element has two special attributes: keytype and challenge. keytype in particular is interesting because the browser uses this entry to decide if it supports this element’s function. Currently, there is only one valid keytype, which is rsa, a cryptographic system developed in 1977 at the Massachusetts Institute of Technology (MIT). If no keytype is specified (as in the preceding example), rsa is used as the default value. The specification also states that a browser does not have to support any keytype at all, which is probably because of Microsoft’s veto against this element. The optional challenge attribute increases security during the key exchange. For further information, please refer to the links in the note at the end of this section.

If the browser supports the RSA key generation, it can offer a selection list to allow the user to select the length, and consequently the security, of the key (see Figure 3.9).

Figure 3.9 Selecting the key length in Google Chrome

image

Figure 3.10 shows the result after the form has been sent: The POST variable kg contains the public key required for encryption (here, rendered in the extremely useful Firefox add-on Firebug).

Figure 3.10 The public key of the “keygen” element, represented in Firebug

image


Note

image

If you have not had much previous experience with cryptography but would like to find out more, Wikipedia is always a good starting point. Check out http://en.wikipedia.org/wiki/Public_key_infrastructure and http://en.wikipedia.org/wiki/Challenge-response_authentication.


3.3.5 Calculations with “output”

“The output element represents the result of a calculation.” That is the very short explanation in the HTML5 specification, and you will find exactly the same text on most websites describing the new element. It all sounds very sensible, but what kind of calculations are we dealing with? Why do we need a special element for them?

As a general rule, these are calculations resulting from input fields on a website. An example familiar to most people would be an electronic shopping cart where the quantity for each product can be entered in an input field. Via the optional for attribute, you can determine which fields to include in the calculation. One or more id attributes of other fields in the document are referenced in the process.

To test the output element, we will program one of these little shopping carts for three different products. The quantity of each of these products can be changed via an input field. At the same time, the total number of items and the total price are displayed under the shopping cart. Figure 3.11 shows a shopping basket with five items.

Figure 3.11 Two “output” elements show the number of products and the price in total

image

The code for our example can be explained quickly and simply: To update the output elements for each change in quantity, we use the form’s oninput event:

<form oninput="updateSum();">
  <table>
    <tr><th>Product<th>Price (US$)<th>Item number
    <tr><td>Keyboard<td class=num id=i1Price>39.50<td>
    <input name=i1 id=i1 type=number min=0 value=0 max=99>
    <tr><td>Mouse<td class=num id=i2Price>26.30<td>

The output elements are defined after the table with the products and refer to the IDs of the input fields via the for attribute:

<p>Your shopping cart contains <output name=sumProd for="i1 i2 i3"
  id=sumProd></output> items. Total price:
  <output name=sum for="i1 i2 i3" id=sum></output> US$.

In the JavaScript code, a loop runs over all input elements, adding the quantities and calculating the total price:

function updateSum() {
  var ips = document.getElementsByTagName("input");
  var sum = 0;
  var prods = 0;
  for (var i=0; i<ips.length; i++) {
    var cnt=Number(ips[i].value);
    if (cnt > 0) {
      sum += cnt * Number(document.getElementById(
        ips[i].name+"Price").innerHTML);
      prods += cnt;
    }
  }
  document.getElementById("sumProd").value = prods;
  document.getElementById("sum").value = sum;
}

We get the product price directly from the table by using the innerHTML value of the relevant table column and converting it to a number with the JavaScript function Number(). The same applies to the value in the input field (ips[i].value), because without this conversion, JavaScript would add up the character strings, which would not produce the desired results. The calculated values are then inserted into the value attributes of the output elements.

3.4 Client-Side Form Validation

One of the advantages of the new elements and attributes in forms is that the user can now enter data much more easily (for example, choose the date from a calendar). Another great advantage is the option of checking the form contents before the form is submitted and alerting the user of any mistakes. You might say that kind of checking is rather old hat because it has been around for years. That is true, but until now this step always had to be done via JavaScript code that you had to program. Thanks to jQuery and similar libraries, this task has become much easier and the code is more manageable, but you still must depend on an external library.

With HTML5, this situation changes fundamentally: You define the parameters of the input fields in HTML, and the browser checks whether the fields have been filled in correctly. That is a big step forward and makes many lines of JavaScript code redundant. This tiny example will convince you:

<form method=get action=required.html>
  <p><label>Your e-mail address:
  <input type=email name=email required></label>
  <p><input type=submit>
 </form>

Figure 3.12 shows what will happen if you submit the form in the preceding listing without specifying an e-mail address. Opera displays the error message: This is a required field. If you have set the Opera user interface to another language, the error message appears in the relevant language. Of course, you can also adapt these error messages with JavaScript; more on this in section 3.4.3.

Figure 3.12 Error message for a blank input field with the “required” attribute (Opera)

image

But that is not all: The field is defined as the type email, so Opera also returns an error message if an invalid e-mail address is entered; for example, Please enter a valid email address (see Figure 3.13).

Figure 3.13 Error message in Opera after entering an invalid e-mail address

image

WebKit-based browsers, such as Google Chrome or Safari, currently support the validation but do not display an error message. They place a border around the invalid field and position the cursor in the field to at least provide some indication that something is not quite right.


Note

image

Despite all the euphoria about client-side validation of form input, you should not forget that this step cannot replace server-side control. A potential attacker can bypass these mechanisms with very little technical effort.


3.4.1 The “invalid” Event

During form validation, elements with an invalid content trigger the event invalid. We can use this to react individually to incorrect values:

window.onload = function() {
  var inputs = document.getElementsByTagName("input");
  for (var i=0; i<inputs.length; i++) {
    inputs[i].addEventListener("invalid", function() {
      alert("Field "+this.labels[0].innerHTML
        +" is invalid");
      this.style.border = 'dotted 2px red';
    }, false);
  }
 }

After loading the page, a list of all input elements is generated (as in the example in section 3.3.5). An event listener is added to each element and deals with the error. In our example it opens an alert window, and the element is marked with a red-dotted border. The label of the input element is used as text in the alert window.

This approach is not ideal in forms with many input fields. The user must click the OK button for each incorrect input and then find the appropriate field in the form and fill in the details again. Sometimes, it would be more useful if the user could be notified immediately of invalid input while filling in the field. We will try this in the next section.

3.4.2 The “checkValidity” Function

To trigger the validation of an input element, the checkValidity function for that element is called. But you can also start “manually” what would normally happen when the form is submitted:

<input type=email name=email
  onchange="this.checkValidity();">

If you enter an invalid e-mail address and move away from the input field (either with the Tab key or by clicking elsewhere in the browser), the browser (currently, at least in Opera) returns an error message right away (refer to Figure 3.13). Error handling becomes even more elegant if we attach a function for checking input to the onchange event of all input elements:

window.onload = function() {
  var inputs = document.getElementsByTagName("input");
  for (var i=0; i<inputs.length; i++) {
    if (!inputs[i].willValidate) {
      continue;
    }
    inputs[i].onchange = function() {
      if (!this.checkValidity()) {
        this.style.border = 'solid 2px red';
        this.style.background = '';
      } else {
        this.style.border = '';
        this.style.background = 'lightgreen';
      }
    }
  }
}

The familiar loop runs over all input elements, checking first whether the element is available for validation. If willValidate does not return the value true, the loop continues with the next element. Otherwise, an anonymous function is assigned to the onchange event, calling the checkValidity function. this within the anonymous function refers to the input element. If the validity check fails, the element is surrounded with a red border; otherwise, the element’s background is colored light green. Remember to reset the background color and border to an empty character string to make sure the browser sets the formatting back to the default value after the user has corrected an incorrect input. In Figure 3.14 you can see how the checkValidity function generates an error message as a result of incorrect time input.

Figure 3.14 Opera displays an error message after an incorrect time input (in this case a violation of the “step” attribute)

image

If you would like to make error handling more interactive, you can use the new HTML5 oninput event instead of the onchange event. Unlike onchange, which is triggered when the field no longer has the focus, oninput is activated after every changed character. The oninput event now does what you previously had to program somewhat laboriously via the keyboard events keyup and keydown. Another advantage of oninput is that the event listener needs to be attached only once to the whole form, not to each input element. So in our preceding example, you could do without all the JavaScript code and change the form definition as follows:

<form method=get oninput="this.checkValidity();"
  action=checkValidity.html >

This means you forgo changing the borders and background color, but you significantly shorten the source code. An immediate reaction to each keystroke can be very helpful in some cases, but when filling in a form field, it is usually enough if the content is checked after the field has been fully completed.

3.4.3 Error Handling with “setCustomValidity()”

If you feel that all the error handling methods introduced earlier are still not quite enough, you can also program your own function for checking content. In the following example, we define an input field with the type email, which ensures that the browser will check for a valid e-mail address. Additionally, we want to specifically exclude three e-mail domains:

var invalidMailDomains = [
  'hotmail.com', 'gmx.com', 'gmail.com' ];

function checkMailDomain(item) {
  for (var i=0; i<invalidMailDomains.length; i++) {
    if (item.value.match(invalidMailDomains[i]+'$')) {
      item.setCustomValidity('E-mail addresses from '
        +invalidMailDomains[i]+' are not accepted.'),
    } else {
      item.setCustomValidity(''),
    }
    item.checkValidity();
  }
}

Each element in the array invalidMailDomains is compared to the value of the input element. The JavaScript function match() works with regular expressions, which is why we add a $symbol to the domain name, to indicate the end of the character string. If the character strings match, the setCustomValidity function is called and displays the appropriate error message. If it is not a domain name from the array, setCustomValidity() is called with an empty character string. Internally, this attaches the variable validationMessage to the input element, which Opera then displays (see Figure 3.15). The concluding call of the checkValidity function triggers the validity check and leads to the aforementioned error message.

Figure 3.15 Opera displays an error message during manual error handling (checking e-mail domain)

image

3.4.4 Summary of Validity Checks

Table 3.3 shows a summary of all input attributes and validity functions available for validity checks, and the scenarios where they occur.

Table 3.3 Possible Errors During Validity Checks of Form Fields

image

3.4.5 Or Perhaps Better Not to Validate? “formnovalidate”

Now that we have spent so much time discussing error handling, we will tell you how you can sneak past all the rules with the attribute formnovalidate. At first it may seem a little strange to simply disregard all the laboriously defined rules and just submit the form without validation. The specification offers a brief explanation that quickly solves the mystery. The typical application for skipping the validity check is a form that the user cannot or does not want to complete in one go. By adding the formnovalidate attribute to a submit button, the content that has been entered so far can be saved for later.


Note

image

If you submit a form with formnovalidate, the fields already completed are sent to the server. The server application is responsible for potentially saving the data temporarily.


Imagine, for example, that you want to fill in a support form for your faulty digital camera. After spending ages filling in all the details about the error that has occurred, the website asks you for the camera’s serial number. Because you do not have the camera at hand and you do not want to lose all the information you have already entered, you click the Save button and can then calmly go looking for your camera. This button is defined as follows:

<p><input type=submit formnovalidate
  value="Save" name=save id=save>

The following example will fully illustrate the idea of the support form.

3.5 Example: A Support Form

In this example, the previously introduced new elements and attributes are used in a form. A form of this kind could, in an expanded state, be used on the website of an electronics dealer.

Initially, the client is asked to supply personal details (in this example just the name, an e-mail address, and a telephone and fax number). The second part of the form concerns the product’s technical data and defect. The bottom part of the webpage shows a progress bar that is meant to encourage the user to complete the form (see Figure 3.16).

Figure 3.16 The almost completed support form

image

The HTML code for the form starts by loading an external JavaScript file and the already familiar call window.onload:

    <script src="support.js"></script>
    <script>
window.onload = function() {
  initEventListener();
}
    </script>

The initEventListener function runs through all input elements and assigns an anonymous function to the onchange event, checking the corresponding element for its validity:

function initEventListener() {
  var inputs = document.getElementsByTagName("input");
  for (var i=0; i<inputs.length; i++) {
    if (!inputs[i].willValidate) {
      continue;
    }
    inputs[i].onchange = function() {
      this.checkValidity();
    }
  }
}

The event listener is only added if the element can check validity. In our example the two buttons for submitting or saving do not have the option to check validity and therefore do not get an onchange event. As explained earlier, checking the individual form fields after they have been filled in is more convenient than checking the entire form with the oninput event.

To improve the form’s user friendliness, we want to emphasize the elements marked as required to make it immediately clear to the user which are the most important fields. Fortunately, we do not have to add an extra style to each element. CSS3 gives us the new selector :required, which is intended for exactly this case. The following instruction places an orange border around all required elements:

:required { border-color: orange; border-style: solid; }

The definition of the individual input fields does not contain any great surprises. E-mail address and phone number have their own types and are required; the date when the defect occurred has the type date and can therefore be selected from a calendar window. The two-column layout in the upper part of the webpage is achieved via adjacent div elements. We still want users who jump to the next field using the Tab key to fill in the form from top to bottom and not, as HTML logic would suggest, first fill in the left and then the right column. We can achieve this with the tabindex attribute, which means that pressing the Tab key in a field will move the cursor to the field with the next higher tabindex value:

<div style="float:left">
<p><label>Your name
<input tabindex=1 type=text required autofocus
  placeholder="John Smith" name=name></label>
<p><label>Your e-mail address
<input tabindex=3 type=email name=email required></label>
</div>
<div style="float:left;margin-left:10px;">
<p><label>Telephone number
<input tabindex=2 type=tel name=tel required></label>
<p><label>Fax number
<input tabindex=4 type=tel name=fax></label>
</div>

Now the code gets more exciting with the textarea fields. HTML5 does not make many changes to this type. But as you can see in Figure 3.16, each text field now has a small graphic display above it, showing how many characters you can still type into this field. You probably realized it right away: It’s done with the new meter element, which you already know from section 3.3.1, Displaying Measurements with “meter”:

<p><label>Error message
<textarea placeholder="Lens error. Camera restart."
  name=errmsg required rows=5 cols=50
  title="up to 200 characters">
</textarea></label><meter value=0 max=200
  tabindex=-1></meter>

The meter element is initialized with a maximum value of 200, exactly the value specified as maximum in the title attribute of the textarea. If a user enters more characters than the maximum allowed, the meter element turns red, indicating that the text entered is too long. The browser will still submit all the text, because we have not limited the textarea. So this is more a hint rather than a strict requirement. The JavaScript function for updating the meter elements is updateTAMeters() and is executed for all textareas:

function updateTAMeters() {
  var textfs = document.getElementsByTagName("textarea");
  for(var i=0; i<textfs.length; i++) {
    textfs[i].labels[0].nextSibling.value =
      textfs[i].textLength;
  }
}

The advantage of the loop is that we can now add any number of textarea elements, and as long as they have a meter element, they will be updated automatically. To achieve this, we need to resort to a DOM trick: The code printed in bold in the preceding listing accesses the DOM function nextSibling, a reference to the next element. Let’s revisit the HTML code for the text field and the status bar to make things clearer. The textarea element is enclosed by a label element followed by the desired meter element. To get from the textarea element to the meter element, we use the text field’s labels property. This is a NodeList array, and we are interested in the first element (with the index 0), because the following element (the nextSibling) is the meter element.

If you look closely, the procedure is not as complicated as it at first looks, but it has a few snags. If there is a stray whitespace or line break that sneaks in between the enclosing label element and the meter element, then our status display no longer works. The nextSibling then becomes a text element, and we can no longer reach the meter element in the for loop.

Next we want to program the progress display at the end of the form. You probably guessed that it is a progress element; More interesting is how we can elegantly express updating this element in JavaScript. First, here is the HTML code for the element:

<label>Progress:
  <progress id=formProgress value=0
    tabindex=-1></progress></label>

We assign to the progress element an id, a starting value of 0 (value), and a negative tabindex, which means that the element is never accessed with the Tab key. The JavaScript function updateProgress() updates the progress element:

function updateProgress() {
  var req = document.querySelectorAll(":required");
  count = 0;
  for(var i=0; i<req.length; i++) {
    if (req[i].value != '') {
      count++;
    }
  }
  var pb = document.getElementById("formProgress");
  pb.max = req.length;
  pb.value = count;
}

Because the progress bar is only supposed to refer to the elements that are absolutely required, we pass the character string :required to the function querySelectorAll(). The result is a NodeList containing only elements that have the required attribute. A loop is then run over these elements, checking whether the value attribute matches a nonempty character string. If this condition applies (in other words, a value has already been entered), the counter variable count is increased by one value. To finish, the maximum value of the progress element is set to the number of all required fields and the value to the number of the nonempty elements.

Two buttons are available for submitting the form: Save and Submit. We have already discussed the save function in section 3.4.5, Or Perhaps Better to Not Validate? “formnovalidate”; new in this context is the attribute accesskey:

<p><input accesskey=T type=submit formnovalidate
  value="Save [S]"  name=save id=save>
<input accesskey=T type=submit name=submit id=submit
  value="Submit [T]">

Keyboard shortcuts are not new in HTML5, but they have not been used much so far. One problem with keyboard shortcuts is that they are activated by different key combinations on different platforms, so you never quite know which key you are supposed to press for a particular shortcut. The HTML5 specification has a suggestion to solve this: The value of the accessKeyLabel should return a character string that corresponds to the correct value on the platform you are using. You could then use this value in the button’s label or in its title attribute. Unfortunately, at the time of this writing, not a single browser was capable of outputting this character string.

Summary

The information we supply in this chapter explains many of the new options provided in HTML5 for forms. Better times are ahead for web developers, because they will no longer need to grapple with JavaScript libraries for common input elements, such as date and time. In particular, the new form functions will be of great help when working with mobile devices where text input is usually much more difficult than on the computer. Form validation in the browser will also contribute significantly to making the code more transparent and therefore more manageable. But do not forget that client-side validation does not make the server application more secure; potential attackers can easily circumvent these checks.

If this chapter has whet your appetite and you want to try out your freshly acquired knowledge of forms on your own website, go right ahead. The syntax of the new elements and attributes is built in such a way that even older browsers will not produce errors. Users of such browsers will not be able to enjoy the full benefit of the new input elements, but text input is always possible.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset