Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Beginning JavaScript With DOM Scripting And Ajax - From Novice To Professional (2006)

.pdf
Скачиваний:
81
Добавлен:
17.08.2013
Размер:
17.27 Mб
Скачать

286

C H A P T E R 7 J A V A S C R I P T A N D U S E R I N T E R A C T I O N : N A V I G A T I O N A N D F O R M S

From a JavaScript point of view, there is not much more you can do with an image input, except that you can provide a rollover state for it.

Select Boxes

Select boxes are probably the most complex and most versatile of form elements. Designers love them, as it lets them store a lot of options for the user to choose from in a small screen space (on the other hand, designers also hate them because they cannot style them with CSS properly).

Each select box has a list object called options that has several properties:

length: The number of all options inside this select box.

selected: Boolean if the option is selected by the user.

selectedIndex: The index number of the selected element. If no element was selected, this returns -1 (which actually is a property of the SELECT element but is appropriate to mention here).

text: The text content of the option.

value: The value of the option.

Note Notice that text and value are properties of each of the options contained in the select box; you cannot read out the chosen value by reading the value property of the select box object itself—as there is no such thing.

There are two kinds of select boxes: single-choice select boxes that only allow one exclusive choice and multiple-choice select boxes that allow the user to choose more than one option by holding down Ctrl and highlighting the options he desires.

Note Multiple-choice select boxes are a nightmare to use for users with assistive technology or keyboard users, which is why you might want to consider using a list of check boxes instead. This will also make it easier to read out the choice on the server side.

C H A P T E R 7 J A V A S C R I P T A N D U S E R I N T E R A C T I O N : N A V I G A T I O N A N D F O R M S

287

Reading out single-choice select boxes is pretty easy. For example, take the select box in the demo form:

exampleSelectChoice.html (excerpt)

<p>

<label for="subject">Subject</label> <select id="subject" name="subject">

<option value="generalEnquiry" selected="selected">General question</option>

<option value="Webdesign">Webdesign</option> <option value="Hosting">Hosting</option> <option value="Training">Training</option>

<option value="Partnership">Partnership</option> <option value="other">Other</option>

</select>

</p>

The quickest way to reach the select box is to use the name of the element instead of the index. The reason is that the element type of select boxes could be either select-one or selectmultiple depending on whether or not the multiple attribute is set. Once you get to the correct object, you can use its selectedIndex property to read out the chosen option and display the value or the text of the option by using the selectedIndex as the list counter:

exampleSelectChoice.html (excerpt)

function checkSingle() {

var f = document.forms[0];

var selectBox = f.elements['subject']; var choice = selectBox.selectedIndex;

alert( 'You chose ' + selectBox.options[choice].text )

}

In the case of multiple-choice select boxes, this isn’t enough, as the user might have chosen more than one option (selectedIndex will return only the first choice).

288

C H A P T E R 7 J A V A S C R I P T A N D U S E R I N T E R A C T I O N : N A V I G A T I O N A N D F O R M S

Instead of using selectedIndex, you’ll have to loop through all the options and test the selected property of each one:

exampleSelectChoice.html (excerpt)

function checkMultiple() { var f = document.forms[0];

var selectBox = f.elements['multisubject']; var choices=[];

for( var i = 0; i < selectBox.options.length; i++ ) { if( selectBox.options[i].selected == 1) {

choices.push( selectBox.options[i].text );

}

}

alert( choices.join(',') );

}

You can reach the select box via its name in the elements collection, and create a new array called choices (the [] is a shortcut notation for new Array()). Loop through each of the options of the select box and check whether its selected property is true. Where that is the case, push the option’s text value as a new array item into choices. Then convert the array to a string using the array’s join() method and display it.

This way of reading the values would also work with a single-choice select box; however, it might be overkill depending on the number of options available. You can put both methods together in a more generic function by reading out the choices depending on the type of the element:

exampleSelectChoice.html (excerpt)

function getSelectValue( fieldName ) { var f = document.forms[0];

var selectBox = f.elements[fieldName]; if( selectBox.type == 'select-one' ) {

var choice = selectBox.selectedIndex;

alert( 'You chose ' + selectBox.options[choice].text );

}else {

var choices = [];

for( var i = 0;i < selectBox.options.length; i++ ){ if( selectBox.options[i].selected == 1 ) {

choices.push( selectBox.options[i].text );

}

}

choices.join( ',' ); alert( choices );

}

}

C H A P T E R 7 J A V A S C R I P T A N D U S E R I N T E R A C T I O N : N A V I G A T I O N A N D F O R M S

289

Adding, Replacing, and Removing Options

Select boxes are unique as form elements go, insofar as they allow you to add or remove options programmatically. You can add a new option by using the Option constructor and including it in the list of options:

extraOption = new Option(value, text, defaultSelected, selected);

If you want, for example, to add “DOM scripting” as a subject to the list, you can do so like this:

exampleSelectChoice.html (excerpt)

function addOption(fieldName) { var f = document.forms[0];

var selectBox = f.elements[fieldName];

var extraOption = new Option('DOM scripting', 'domscripting', 0, 0); selectBox.options[ selectBox.options.length ] = extraOption;

}

You can remove an option by setting it equal to null:

exampleSelectChoice.html (excerpt)

function removeOption(fieldName,i) { var f = document.forms[0];

var selectBox = f.elements[fieldName]; selectBox.options[i] = null;

}

Replacing options is as easy; simply set the old option to the new one:

exampleSelectChoice.html (excerpt)

function replaceOption( fieldName, i ) { var f = document.forms[0];

var selectBox = f.elements[fieldName];

var extraOption = new Option( 'DOM scripting', 'domscripting', 0 ,0 );

selectBox.options[i] = extraOption;

}

Inserting an option before another option is a bit more problematic, as you need to copy all the options before you rewrite the options collection. The function insertBeforeOption() takes two parameters: the name of the form element and the index of the option you want to insert the new option before. You start by defining two loop counters called i and j and a blank array called opts before finding the select box and creating the new option.

290 C H A P T E R 7 J A V A S C R I P T A N D U S E R I N T E R A C T I O N : N A V I G A T I O N A N D F O R M S

exampleSelectChoice.html (excerpt)

function insertBeforeOption( fieldName, n ) { var i = 0, j = 0, opts = [],

var f = document.forms[0];

var selectBox = f.elements[fieldName];

var extraOption = new Option('DOM scripting', 'domscripting', 0,0);

Then store the options of the select box in a variable called old and loop through them, creating a new option for each of them and assigning their properties to the new option.

exampleSelectChoice.html (continued)

var old = selectBox.options;

for( i = 0; i < old.length; i++ ) {

opts[i] = new Option(old[i].text, old[i].value, old[i].defaultSelected, old[i].selected );

}

The new list will be one element longer, which is why you increase the length property before looping through the new list. You test whether the loop counter is the same as the parameter sent to the function and insert the new option if this is the case.

exampleSelectChoice.html (continued)

old.length++;

for( i = 0; i < old.length; i++ ) { if( i == n ) {

old[i] = extraOption;

Otherwise, you set the option to the old option and increase the j counter variable. Notice you need a second counter here because you cannot change the variable i during the loop. As the new option list will be one item bigger, you need to use j to get the value stored in the opts array.

C H A P T E R 7 J A V A S C R I P T A N D U S E R I N T E R A C T I O N : N A V I G A T I O N A N D F O R M S

291

exampleSelectChoice.html (continued)

}else {

old[i] = opts[j]; j++;

}

}

}

Depending on the number of options in the select box, this could become a rather slow and demanding script. You can achieve the same effect a lot quicker and with less code by using the DOM:

exampleSelectChoice.html (excerpt)

function insertBeforeOptionDOM( fieldName, i ) {

var selectBox = document.getElementById( fieldName ); if( !selectBox ){ return false; }

var opt = selectBox.getElementsByTagName( 'option' ); var extraOption = document.createElement( 'option' ); extraOption.setAttribute( 'value', 'domscripting' ); extraOption.appendChild( document.createTextNode( 'DOM Scripting' ) );

selectBox.insertBefore( extraOption, selectBox.options[i] );

}

Select boxes are a big part of web application development and have traditionally been the interface for sorting two lists by moving elements back and forth.

Interactive Forms: Hiding and Showing Dependent Elements

One really cool thing about JavaScript and forms is that you can make forms a lot more engaging and dynamic than they are “out-of-the-box.” It is tempting to make everything interact with each other and immediately send a form without expecting the user to click a Submit button or press Enter. The danger of this is not only do you sacrifice support for user agents other than visual ones, but also users may send data prematurely.

292

C H A P T E R 7 J A V A S C R I P T A N D U S E R I N T E R A C T I O N : N A V I G A T I O N A N D F O R M S

When it comes to simply changing the interface or the number of options displayed in a form, it is quite safe to use change handlers. Let’s use the demo form as an example. You might have noticed that there are some fields that have a logical connection: the “other subject” text field only makes sense when the “Other” option has been selected, and the choice to receive the newsletter as HTML or plain text comes into play only when the user has chosen to subscribe to the newsletter.

exampleDynamicForm.html (excerpt)

<form method="post" action="send.php"> [... code snipped ...]

<p><label for="subject">Subject</label> <select id="subject" name="subject">

<option value="generalEnquiry" selected="selected">General question</option>

<option value="Webdesign">Webdesign</option> <option value="Hosting">Hosting</option> <option value="Training">Training</option>

<option value="Partnership">Partnership</option> <option value="other">Other</option>

</select></p>

<p><label for="otherSubject">specify other subject</label> <input type="text" id="otherSubject" name="otherSubject" /></p> [... code snipped ...]

<p><input type="checkbox" name="newsletter" value="yes" id="newsletter" />

<label for="newsletter">Sign me up for the newsletter</label></p> <p>Newsletter format:

<input type="radio" name="newsletterFormat" id="newsHtml" value="html" checked="checked" />

<label for="newsHTML">HTML</label>

<input type="radio" name="newsletterFormat" id="newsPlain" value="plain"/>

<label for="newsPlain">Text</label></p>

With a script you can hide these options and make them appear only when the user has selected the appropriate option. Figure 7-9 shows how that looks in a browser.

C H A P T E R 7 J A V A S C R I P T A N D U S E R I N T E R A C T I O N : N A V I G A T I O N A N D F O R M S

293

Figure 7-9. Showing and hiding form elements depending on user choices

You define a class to apply to the elements you want to hide and the IDs of the two dynamic elements as properties of a main object called df.

dynamicForm.js

df = {

hideClass : 'hide', letterOption : 'newsletter', subjectOption : 'subject',

The init() method checks for DOM support and whether the necessary elements are available.

dynamicForm.js (continued)

init : function() {

if( !document.getElementById || !document.createTextNode ){ return;

}

df.news = document.getElementById( df.letterOption ); df.subject = document.getElementById( df.subjectOption ); if( !df.subject || !df.news ){ return; }

294

C H A P T E R 7 J A V A S C R I P T A N D U S E R I N T E R A C T I O N : N A V I G A T I O N A N D F O R M S

Next you need to find the elements to hide. By using the DOMhelp method closestSibling(), you can make sure you don’t try to hide line breaks but the elements that you actually want to reach. Store the elements in properties of the main object to make them accessible to the event handler methods.

You can hide the elements by adding the hiding class to them and assign a click event handler that points to the letterChange() method to the check box and a change handler that points to subjectChange() to the select box.

dynamicForm.js (continued)

df.newsOpt = DOMhelp.closestSibling( df.news.parentNode, 1 ); df.subjectOpt = DOMhelp.closestSibling( df.subject. parentNode, 1 );

DOMhelp.cssjs( 'add', df.newsOpt, df.hideClass ); DOMhelp.cssjs( 'add', df.subjectOpt, df.hideClass ); DOMhelp.addEvent( df.news, 'click', df.letterChange, false );

DOMhelp.addEvent( df.subject, 'change', df.subjectChange, false );

},

You retrieve the check box via getTarget() in the letterChange() method before testing its checked property. If the property is checked, you remove the hiding class; otherwise you add it.

dynamicForm.js (continued)

letterChange : function( e ){

var t = DOMhelp.getTarget( e );

var action = t.checked ? 'remove' : 'add'; DOMhelp.cssjs( action, df.newsOpt, df.hideClass );

},

The subjectChange() method works the same way; you retrieve the target and check whether the fifth option is the selected one (that is, whether selectedIndex is equal to 4). If it is, you remove the hiding class from the optional element; otherwise you add it. As an extra, the method sets the focus of the browser to the newly shown element so that users can immediately start typing.

C H A P T E R 7 J A V A S C R I P T A N D U S E R I N T E R A C T I O N : N A V I G A T I O N A N D F O R M S

295

dynamicForm.js (continued)

subjectChange : function( e ) { var t = DOMhelp.getTarget( e );

var action = t.selectedIndex == 5 ? 'remove' : 'add'; DOMhelp.cssjs( action, df.subjectOpt, df.hideClass ); if(action == 'remove' ) {

df.subjectOpt.getElementsByTagName( 'input' )[0].focus();

}

}

}

DOMhelp.addEvent(window, 'load', df.init, false );

Showing and hiding the connected elements is one way to make parts of a form connected to other options. A different approach is to keep them visible but add a disabled attribute. This makes them impossible to change for the user, and the browser shows them grayed out.

This is a bit less versatile than just hiding elements, as the disabled attribute is only applicable to input, textarea, select, option, optgroup, and button. Figure 7-10 shows how the form looks with disabled elements in Firefox on Windows.

Figure 7-10. Disabling elements instead of hiding them