Some time ago Tom Hofte wrote a post on implementing dependent select boxes using ajax in struts. In this post i’ll show you how to do it with JSF. But i’ll do it the easy way, using ADF Faces. ADF Faces is pretty powerful, you don’t have to handcode any javascript to create dependent select boxes.
Here’s a screenshot of the page i’m going to create. The page contains two select boxes, the first contains a couple of countries, the second contains names of cities. The idea is that when you select a country, the second combobox will be automatically populated with a list of cities belonging to the country you selected.

The sourcecode of the JSF page:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%@ page contentType="text/html;charset=windows-1252"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://xmlns.oracle.com/adf/faces" prefix="af"%>
<%@ taglib uri="http://xmlns.oracle.com/adf/faces/html" prefix="afh"%>
<f:view>
<afh:html>
<afh:head title="Select country and city">
<meta http-equiv="Content-Type"
content="text/html; charset=windows-1252"/>
</afh:head>
<afh:body>
<h:form>
<af:messages/>
<af:selectOneChoice
label="Country" value="#{page1BackingBean.country}"
id="countryDropDown"
binding="#{page1BackingBean.countryBinding}"
autoSubmit="true"
valueChangeListener="#{page1BackingBean.countryChangeListener}">
<f:selectItems value="#{page1BackingBean.countrySelectItems}"/>
</af:selectOneChoice>
<af:selectOneChoice
label="City" value="#{page1BackingBean.city}"
id="citiesDropDown" binding="#{page1BackingBean.cityBinding}"
partialTriggers="countryDropDown" autoSubmit="true">
<f:selectItems value="#{page1BackingBean.citySelectItems}"/>
</af:selectOneChoice>
<af:outputText
value="country: #{page1BackingBean.country}, city: #{page1BackingBean.city}"
partialTriggers="countryDropDown citiesDropDown"/>
</h:form>
</afh:body>
</afh:html>
</f:view>
When you select a country, the server is immediately informed of your choice. This is caused by the autoSubmit attribute on the first selectOneChoice tag. On the server the valueChangeListener for country is invoked, which populates the second dropdown box with the correct list of cities. Now the second combobox needs to be redrawn to display the new cities. You handle this with the partialTriggers on the second selectOneChoice. The partialTrigger attribute indicates that the component needs to be updated when the component with id countryDropDown has changed. I’ve done the same for the outputText component, to make sure the text also displays the latest values in the comboboxes.
The source code for the backing bean:
import java.util.ArrayList;
import java.util.Collection;
import javax.faces.component.UISelectItems;
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;
import oracle.adf.view.faces.component.core.input.CoreSelectOneChoice;
public class Page1BackingBean {
//values
String country;
String city;
SelectItem[] countrySelectItems;
SelectItem[] citySelectItems;
//bindings
private CoreSelectOneChoice countryBinding;
private CoreSelectOneChoice cityBinding;
// data
SelectItem[] countries =
new SelectItem[] { new SelectItem("Netherlands"), new SelectItem("Belgium") };
SelectItem[] nlCities =
new SelectItem[] { new SelectItem("Amsterdam"), new SelectItem("The Hague") };
SelectItem[] beCities =
new SelectItem[] { new SelectItem("Gent"), new SelectItem("Brugge") };
public Page1BackingBean() {
countrySelectItems = countries;
citySelectItems = null;
}
public void setCountry(String country) { this.country = country; }
public String getCountry() { return country; }
public void setCity(String city) { this.city = city; }
public String getCity() {return city;}
public void setCountryBinding(CoreSelectOneChoice countryBinding) {
this.countryBinding = countryBinding;
}
public CoreSelectOneChoice getCountryBinding() {
return countryBinding;
}
public void setCityBinding(CoreSelectOneChoice cityBinding) {
this.cityBinding = cityBinding;
}
public CoreSelectOneChoice getCityBinding() {
return cityBinding;
}
public SelectItem[] getCountrySelectItems() {
return countrySelectItems;
}
public SelectItem[] getCitySelectItems() {
System.err.println("getCitySelectItems: ");
if (countryBinding.getValue() != null) {
if (countryBinding.getValue().equals("Netherlands")) {
citySelectItems = nlCities;
} else if (countryBinding.getValue().equals("Belgium")) {
citySelectItems = beCities;
}
}
return citySelectItems;
}
public void countryChangeListener(ValueChangeEvent evt) {
cityBinding.setValue(null);
}
}
Two methods are of interest here. The getCitySelectItems method returns the correct list of cities depending on the value of country. The countryChangeListener resets the city combobox when a new country has been selected. For this countryChangeListener to function correctly, the backing bean needs to be created in the session scope:
<?xml version="1.0" encoding="windows-1252"?>
<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
"http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config xmlns="http://java.sun.com/JSF/Configuration">
<application>
<default-render-kit-id>oracle.adf.core</default-render-kit-id>
</application>
<managed-bean>
<managed-bean-name>page1BackingBean</managed-bean-name>
<managed-bean-class>Page1BackingBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
</faces-config>
I’m actually not too happy about the session scope. It means that you’ll get very weird effects when you open this page in two windows or two tabs. I’m a big user of browser tabs. For example, when i use our bug database, i’ll often open multiple “edit bug” pages in different tabs at the same time. This is probably not a thing you should do in a JSF application.

April 6th, 2006 at 14:27:03
I am using ADF selectOneChoice and populating textfields etc. based on the selection in the SelectOneChoice. But it is not possible for me to create my BackingBean in session – it needs to be request scope. Is there any way of doing thi? Pls help.
April 6th, 2006 at 15:02:53
Populating the textfields should work with request scope. This problem is making valueChangeListeners work, i think this requires session scope. But as long as you’re not using the valueChangeListener, request scope might work.
April 7th, 2006 at 10:04:43
I am using a ValueChangeListener method – but is there an alternative to this? How else can we generate an action based on a change in the SelectOneChoice
April 8th, 2006 at 11:44:58
is there any way to access the request from the constructor of the backing bean?
August 27th, 2006 at 12:08:10
It works only if size of city list is always the same. What in other case???
August 30th, 2006 at 19:26:15
Hi, great stuff, I was wondering how you would do this if the drop downs were in a table. How would you set the partialTriggers when the Id would change?
Thanks!
September 12th, 2006 at 08:28:47
Hello Sir,
Thanks a lot for such a code. It was useful.
June 2nd, 2007 at 20:29:50
hi
as I can insert the values of the selectOneChoice in the database
January 17th, 2008 at 06:52:21
Hi, I tried the above ex.. but my countryBinding.getValue() is coming null in ublic SelectItem[] getCitySelectItems(). What can be the reason for it.
Please reply me soon on my mail Id,….
minalk@acrotechnologies.com
Thanks in advance
February 23rd, 2008 at 08:55:23
hai,
no items is displayed in city select drop down list box when i choose country in the country drop down list box.
can u help me
iam using netbeans6.0
February 27th, 2009 at 14:07:59
The code provided in this site is useful. It can be understand eaisly. It works fine.
Regrads
Aswini
June 4th, 2009 at 07:10:40
Hi All,
I’m developing an application that needed dependent select boxes like this. I’m using NetBeans 6.5 + JSF 1.2. My question is how to include ADF lib and use it in NB. Is there a better way do implement dependent Select boxes in the NB? Thank you.
November 30th, 2009 at 17:49:19
The backing bean should NOT be set as session scope. Set as request scope. You can bind the value of the selectOneChoice (country & city) to session variables instead of the local variable in the backing bean. The items in the combo box of the city are defined in the backing bean, but the content is depending on the current value of country selection in the session. I writed dependency components all the time for 2.5 years. It works and I use JDeveloper 10.1.3.0
May 26th, 2010 at 10:32:31
there is the problem in the above code i have
when we select the netherlands and not go to the city again select the other then the same city it show it is not showing the other city
but if i select the city and again select the brazil then it show the brazil city
my code is
May 26th, 2010 at 10:34:29
Insert title here
my bean is
package UserBean;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;
import org.apache.myfaces.trinidad.component.core.input.CoreSelectOneChoice;
public class UserBean {
private String city;
private String country;
SelectItem[] countrySelectItems;
SelectItem[] citySelectItems;
private CoreSelectOneChoice countryBinding;
private CoreSelectOneChoice cityBinding;
SelectItem[] countries =
new SelectItem[] { new SelectItem(“India”), new SelectItem(“Belgium”) };
SelectItem[] nlCities =
new SelectItem[] { new SelectItem(“delhi”), new SelectItem(“noida”) };
SelectItem[] beCities =
new SelectItem[] { new SelectItem(“Gent”), new SelectItem(“Brugge”) };
public UserBean() {
countrySelectItems = countries;
citySelectItems = null;
}
public void setCountry(String country) {
this.country = country;
}
public String getCountry() {
return country;
}
public void setCity(String city) {
this.city = city;
}
public String getCity() {
return city;
}
public void setCountryBinding(CoreSelectOneChoice countryBinding) {
this.countryBinding = countryBinding;
}
public CoreSelectOneChoice getCountryBinding() {
return countryBinding;
}
public void setCityBinding(CoreSelectOneChoice cityBinding) {
this.cityBinding = cityBinding;
}
public CoreSelectOneChoice getCityBinding() {
return cityBinding;
}
public SelectItem[] getCountrySelectItems() {
return countrySelectItems;
}
public SelectItem[] getCitySelectItems() {
if (countryBinding.getValue() != null) {
if (countryBinding.getValue().equals(“India”)) {
citySelectItems = nlCities;
} else if (countryBinding.getValue().equals(“Belgium”)) {
citySelectItems = beCities;
}
}
return citySelectItems;
}
public void countryChangeListener(ValueChangeEvent evt) {
cityBinding.setValue(null);
}
}
and the face-config.xml is
page1BackingBean
UserBean.UserBean
request
May 26th, 2010 at 10:35:10
can any one help me