The phrase combo box is used here
to denote a construct in a form, allowing the user to make a choice
among predefined alternatives or type his own alternative.
In HTML terms, this would mean
a combination of a select
element and
an input type="text"
element.
In HTML at present, you can only include such elements as
two separate,
mutually independent constructs.
You can however include JavaScript code which
checks the consistency on submit
or, better still,
dynamically modifies the form
so that the text input field is enabled if and only
if the select
menu choice is particular one
(like "None of the above, please specify:").
In some situations the field could be invisible when it is disabled.
Quite often nowadays, "combo box" seems to mean just a dropdown
menu (pulldown menu) created by a select
element.
But it seems that the original meaning is "combination box" as
outlined above, and that's the meaning used here.
The need for such constructs arises naturally when you set
up a form where a question should normally be answered by selecting
one of given alternatives but it is possible that none applies,
in which case you'd like to ask the user to type his choice in
his own words.
There is also a different idea
of combining free text input and
menu selection: using a text field so that it can be
filled either by typing directly or by selecting an option from
a menu which causes the text field to be filled. An approach similar
to the one discussed here could be applied: include the text field
normally, and if JavaScript is enabled, include dynamically a
select
menu so that when a selection is made,
the text field is filled with text corresponding to the option
selected. The main problem with that approach, as compared with the
one discussed in this document, is that the user could not make
a choice from a menu when JavaScript is disabled.
Due to the simplicity of the
form concept in HTML, you cannot set up a genuine combo box in HTML.
You can just set up two separate fields.
This means that the server-side form handler should, among the
data consistency checks it performs, verify that the data from the
text input field is present and nonempty if and only if the
choice from the select
menu was
"None of the above, please specify:" or whatever you decided to put there.
This is something you should do in any case, as a fallback
for situations where more advanced methods do not work. This does
not mean writing separate pages for different browsing situations.
Instead, you use some nice constructs within a single page so that
the page "behaves" differently. And the simple fallback, consisting
of two fields, should be done first, because it makes this
part of the form fully functional, though not optimal, and it is
needed anyway, and the enhancements will be built around it.
It could be something like the following:
<form action="http://jkorpela.fi/cgi-bin/checkcombo.pl"><div>
<select name="menu">
<option value="0" selected>(please select:)</option>
<option value="1">one</option>
<option value="2">two</option>
<option value="3">three</option>
<option value="other">other, please specify:</option>
</select>
<input type="text" name="choicetext"></div>
<div><input type="submit" value="submit"></div>
</form>
This is how it looks like on your browser:
(If you try to submit it, you will get the form data echoed back, together with a note telling whether the data would be rejected or accepted by the server-side checks discussed below.)
The server-side form handler would then to
check first
that the value of the menu
field is not 0
(indicating that the user made no choice). Then it would use the
value of that field for further processing, unless the value was
other
, in which case the value of the choicetext
field would be used, perhaps after some preprocessing. And it should
check that menu
has value other
if and only
if the value of choicetext
is nonempty.
It naturally depends on the application what should be done if
one of the checks fails.
We will not go into these issues here. Instead, we assume that you have
this robust, though simplistic, implementation done and tested,
and consider the optional client-side enhancements.
However, for readers with basic understanding of
Perl,
here's a simple piece of code for doing the checks in Perl
(with the $in
hash containing the form fields
as received and with resulting return page being cumulated to
variable $output
):
if($in{'menu'} eq 0) { $output .= "<p><strong>Rejected</strong>: no selection made.</p>\n"; } elsif($in{'menu'} eq 'other' && (!defined($in{'choicetext'}) || length($in{'choicetext'}) == 0)) { $output .= "<p><strong>Rejected</strong>: option \"other\"". "selected but text input box not filled.</p>\n"; } elsif($in{'menu'}!='other' && defined($in{'choicetext'}) && length($in{'choicetext'})>0) { $output .= "<p><strong>Rejected</strong>: option \"other\"". "not selected but text input box filled.</p>\n"; } else { $output .= "<p>Accepted.</p>"; }
When a form submission is rejected due to such checks, the user can probably use the Back button (or its equivalent) to get back the form with his data, fix it, and submit anew. A more robust solution would work so that the page returned by the script does not only explain what's wrong but also contains a copy of the form, with user-supplied data prefilled and unacceptable data highlighted. Exactly how this should be done depends on the application, of course.
A simple client-side enhancement is to perform on form submission
checks which correspond to the server-side checks. The purpose is
to give the user faster feedback. An error in filling a form
is probably easier to fix when it is reported immediately.
For our sample form, we could just add the attribute
onsubmit="return valid(this.menu,this.choicetext)"
into the form
tag and include the following
JavaScript code
(via a
script
element):
function last_choice(selection) { return selection.selectedIndex==selection.length - 1; } function valid(menu,txt) { if(menu.selectedIndex == 0) { alert('You must make a selection from the menu'); return false;} if(txt.value == '') { if(last_choice(menu)) { alert('You need to type your choice into the text box'); return false; } else { return true; }} else { if(!last_choice(menu)) { alert('Incompatible selection'); return false; } else { return true; }}}
This presumes that the "Something else" choice in the menu is the last one in the menu, as it usually is.
You can test it on your browser:
We could consider various enhancements to this approach,
such as performing these checks
also when the select
menu choice
or the text input field is changed or when the field after them
is focused on. That would give even faster feedback to the user.
But here we shall consider the approach which lets us, in some
cases, prevent the user from making errors.
Ideally, we would like to make a combo box appear so that
initially there is just a select
menu, and when
a choice like "Other" is selected, a text input box appears
(alongside with the menu, or instead of it) for user input.
We use "DHTML" techniques in an attempt to make the text input field both disabled and invisible unless the "Other" choice is selected. The relatively simple technique used for that here works on all reasonably modern versions of commonly used browsers, including IE from version 4 upwards. (To create something similar on very old versions of Netscape would require an extra effort.) We additionally use simpler JavaScript techniques which prevent the field from being focused on; this should work on all JavaScript-enabled browsers. (Compare to techniques for making a field readonly.) The code means the following additions to what we discussed above:
name="demoform"
into the
form
tag.
select
tag:
onchange="process_choice(this,document.demoform.choicetext)"
function activate(field) { field.disabled=false; if(document.styleSheets)field.style.visibility = 'visible'; field.focus(); } function process_choice(selection,textfield) { if(last_choice(selection)) { activate(textfield); } else { textfield.disabled = true; if(document.styleSheets)textfield.style.visibility = 'hidden'; textfield.value = ''; }} function check_choice() { if(!last_choice(document.demoform.menu)) { document.demoform.choicetext.blur(); alert('Please check your menu selection first'); document.demoform.menu.focus(); }}
<noscript> <input type="text" name="choicetext"> </noscript> <script type="text/javascript" language="JavaScript"> disa = ' disabled'; if(last_choice(document.demoform.menu)) disa = ''; document.write('<input type="text" name="choicetext"'+disa+ ' onfocus="check_choice()">'); if(disa && document.styleSheets) document.demoform.choicetext.style.visibility = 'hidden'; </script>
You can test this on your browser (the code is also available as a separate document):
This works best on modern JavaScript-enabled browsers;
then the text input field is
not visible at all unless "other, please specify:" is selected.
In the currently rare case of a JavaScript-enabled browser that does
not support the CSS property
visibility
,
the text input field is there all the time
but you cannot write into it, or even focus on it, unless
"other, please specify:" is selected.
The reason is that even if the visibility
property won't
work, the browser will still process the event of focusing on the
text input field. That means executing the check_choice()
function.
And when JavaScript is
unsupported or disabled, there is just a select menu and an
input box, and the server-side script needs to take it from there.
Since practically all JavaScript-enabled browsers support
the invisibility
property,
you could simplify the approach as follows:
input
field in HTML markup-
Note: One might also consider using the display
property for the text input
field, setting it to none
initially (in JavaScript)
and changing it to inline
when needed. However,
changing the value of the display
property generally
requires reformatting (redraw) of the page, whereas visibility only
affects the particular element.<(p>