It has always been a bit of a tricky discussion, when to use a group of Radio Buttons and when to use a Select (List) in an HTML Form. Radio Buttons are easier to select. Besides, all available values are displayed without user action. However, for more than up to four or five values, radio groups typically take too much place in the page.
I sat down considering this dilemma, especially since in many cases where the user is allowed to choose from more than five options, he typically uses only some of them in the majority of cases. So I figured: why not combine the radio buttons for these most popular values (say the first three or so) with a select element for the other values (up to 15 or so; above that number you are probably better off with a popup window with a List of Values). I have not seen this combination before, so in my own way I have invented it. However, that is not to say it does not already exist. In that case, forgive me my smugness.
In this article I will explain how you can pretty easily combine Radio Buttons and Select to provide a single element from which the user can select an element. I will show this using plain HTML and JavaScript as well as in the context of a Struts JSP.
Combining Radio Buttons with a Select
Here we see the Radio Buttons, each of them is called EmpJob. They are contained in the EmpBean Form. There are three popular values: Clerk, Manager and Seller. These are represented using Radio Buttons. The other six values that the user may select are less popular. These are contained in the select item that is displayed behind the last radio button. Initially, the select item is disabled. Only when the last radio button is checked, is the select item enabled; this is done by the onClick event trigger on the last radio button.
When the selected value in the select element is changed, the onChange event fires the trigger. This trigger copies the selected value to the last radio button. Note that when the form is submitted, the value in the (checked) radio button is the one that matters; the selected option in the select item is not relevant at all!
<td nowrap="nowrap"> <input type="radio" name="EmpJob" value="CLERK" onclick="document.EmpBean.EmpJobSelect.disabled=true;">Clerk<BR/> <input type="radio" name="EmpJob" value="MANAGER" onclick="document.EmpBean.EmpJobSelect.disabled=true;">Manager<BR/> <input type="radio" name="EmpJob" value="SALESMAN" onclick="document.EmpBean.EmpJobSelect.disabled=true;">Seller<BR/> <input type="radio" name="EmpJob" value="" onclick="document.EmpBean.EmpJobSelect.disabled=false;"> <select name="EmpJobSelect" disabled="true" onchange="document.EmpBean.EmpJob[document.EmpBean.EmpJob.length-1].value= document.EmpBean.EmpJobSelect.options[document.EmpBean.EmpJobSelect.selectedIndex].value; "> <option value="">Other, select....</option> <option value="ANALYST">Analyzing Staff</option> <option value="CONSULTNT">Consultant</option> <option value="PRESIDENT">Top Boss</option> <option value="ACCOUNTNT">Bookkeeper</option> <option value="CATERER">Caterer</option> <option value="PROFFICER">PR Person</option> </select> <script>setSelectValue('ACCOUNTNT',document.EmpBean.EmpJobSelect, document.EmpBean.EmpJob);</script> <BR/> </td>
Upon loading the HTML Document, the call to the setSelectValue function immediately following the select item takes care of initializing the select item as well as the radio group: if the current value (in the example that is ACCOUNTNT) is not one of the popular ones represented by radio buttons but instead one that is part of the select item, the last radio button is (pre)selected, the select elements is properly initialized and it is enabled.
<script> <!-- //this function will see whether the value parameter is found in the select element selectItem. // If it is, the radioItem must have its last radio button checked, and its value must be set to the value parameter. // The selectItem must be enabled and it must be set to the option whose value equals the value parameter. function setSelectValue(value, selectItem, radioItem) { // if the value is in the selectItem // then: - enable the select item // - set the Other radio button's value to the value // - set the Other Radio button to checked // - set the select item's option to selected // else nothing really found = false; for (i=0;i<selectItem.options.length;i++) { if (selectItem.options[i].value==value) { radioItem[radioItem.length-1].checked=true; radioItem[radioItem.length-1].value=value; selectItem.options[i].selected=true; selectItem.disabled=false; found = true; i=selectItem.options.length+1; }//if }//for } // --> </script>
The Struts Tags based JSP for this HTML
The HTML you see above was produced from a JSP. In this case the domain values are hard coded in the JSP. We will later see an example where the allowable values are instead retrieved from a Model object. This Struts oriented JSP looks as follows:
<script> <!-- function setSelectValue(value, selectItem, radioItem) { // if the value is in the selectItem // then: - enable the select item // - set the Other radio button's value to the value // - set the Other Radio button to checked // - set the select item's option to selected // else nothing really found = false; for (i=0;i<selectItem.options.length;i++) { if (selectItem.options[i].value==value) { radioItem[radioItem.length-1].checked=true; radioItem[radioItem.length-1].value=value; selectItem.options[i].selected=true; selectItem.disabled=false; found = true; i=selectItem.options.length+1; }//if }//for } // --> </script>
and inside the <html:form name="EmpBean">
tag:
<td nowrap="nowrap"> <html:radio name="EmpBean" property="EmpJob" value="CLERK" onclick="document.EmpBean.EmpJobSelect.disabled=true;" />Clerk<BR/> <html:radio name="EmpBean" property="EmpJob" value="MANAGER" onclick="document.EmpBean.EmpJobSelect.disabled=true;"/>Manager<BR/> <html:radio name="EmpBean" property="EmpJob" value="SALESMAN" onclick="document.EmpBean.EmpJobSelect.disabled=true;"/>Seller<BR/> <html:radio name="EmpBean" property="EmpJob" value="" onclick="document.EmpBean.EmpJobSelect.disabled=false;"/> <select name="EmpJobSelect" disabled="true" onchange="document.EmpBean.EmpJob[document.EmpBean.EmpJob.length-1].value= document.EmpBean.EmpJobSelect.options[document.EmpBean.EmpJobSelect.selectedIndex].value; "> <option value="">Other, select....</option> <option value="ANALYST">Analyzing Staff</option> <option value="CONSULTNT">Consultant</option> <option value="PRESIDENT">Top Boss</option> <option value="ACCOUNTNT">Bookkeeper</option> <option value="CATERER">Caterer</option> <option value="PROFFICER">PR Person</option> </select> <script>setSelectValue('<bean:write name="EmpBean" property="EmpJob" />',document.EmpBean.EmpJobSelect, document.EmpBean.EmpJob);</script> <BR/> </td>
Using the Radio Button-Select combination with Oracle ADF – and dynamic domains
Here we will take a brief look at a JSP page created using Oracle ADF and plenty of JSTL (no Struts tags this time). In fact, this page was generated using JHeadstart, but could very well have been hand built.
In this case, the domain values are not static but instead supplied by a an ADF BC View Object. This ViewObject contains a query that returns three attributes: Value, Meaning and Category. The Category is either 1 – for values that are popular and should be in the Radio Buttons – or 2 – for less popular values that should be in the Select. In our case, the page is based on the EMP table and the domain is on the JOB column. The domain ViewObject is based on the following query:
select distinct job value , initcap(job) meaning , case when (select count(*) from emp e2 where e2.job = emp.job) > 2 then '1' else '2' end Category from emp
In our case, we find three Job values in category 1 (Radio Button) and another three in category 2 (Select). We have created Action Bindings for the ViewObject and its three Attributes.
The JSP contains the following code for creating the Radio Buttons and the Select:
<td nowrap="nowrap"> <c:set var="jobFound" value="false" /> <c:forEach var="atv" items="${bindings.JobDomainViewObj1.rangeSet}"> <c:if test="${atv.Category eq 1}" > <input type="radio" name="EmpJob" value="<c:out value="${atv.Value}"/>" onclick="document.EmpBean.EmpJobSelect.disabled=true;" <c:if test="${bindings.EmpJob eq atv.Value}"> checked="true" <c:set var="jobFound" value="true" /> </c:if> /> <c:out value="${atv.Meaning}"/><BR/> </c:if> </c:forEach> <input type="radio" name="EmpJob" value="<c:out value="${bindings.EmpJob}" />" onclick="document.EmpBean.EmpJobSelect.disabled=false;" <c:if test="${!jobFound}"> checked="true" </c:if> /> <select name="EmpJobSelect" disabled="true" onchange="document.EmpBean.EmpJob[document.EmpBean.EmpJob.length-1].value= document.EmpBean.EmpJobSelect.options[document.EmpBean.EmpJobSelect.selectedIndex].value;"> <option value="">Other, select....</option> <c:forEach var="atv" items="${bindings.JobDomainViewObj1.rangeSet}"> <c:if test="${atv.Category eq 2}" > <option value="<c:out value="${atv.Value}" />" <c:if test="${bindings.EmpJob eq atv.Value}"> selected="true" </c:if> > <c:out value="${atv.Meaning}"/></option> </c:if> </c:forEach> </select> <script>enableSelect(document.EmpBean.EmpJobSelect);</script> </td>
See the working HTML: RadioAndSelect HTML
Download a JDeveloper 10.1.2 + JHeadstart 10.1.2 project to see the actual code for this last situation: HTML_JavaScriptTrial.zip
Next steps…
In a next article we will take this further in two directions. One is to add the Other… option where the user can provide his own value, by typing it into a text field. The other direction is the solution to the dilemma between the convenience of the Select item up to 10 to 20 items and the popup window with list of values for larger numbers of values. In the same spirit as the Radio Button with Other Options, we can have a Select Option (“Other”) that when selected will cause a popup window to be opened. A third direction by the way would be to try this in UIX and/or ADF Faces.
fine code
This kind of functionality has been built-in to the qForms JSAPI library for a long time. While the example below doesn’t show a select box as the “other” choice, it’s actually pretty trivial to change (just change the field from a text field to a select box.)
http://www.pengoworks.com/qforms/docs/examples/advanced.htm
Nice one. Will speed up batch form processing apps. (Although power users might prefer only a selector due to keyboard shortcuts.)
One suggestion: Why not let the user click on the selector directly, instead of going through the radiobutton?
The article you refer to describes a Swing based implementation of an element that supports multi-select through checkboxes. While in the same category perhaps, it is quite something else than the HTML based single select item that I describe in this article.
This looks better (ie uses less space) than the radio-select described in this article: http://www.orablogs.com/duffblog/archives/001203.html. Though the idea is not new.