By Shadooo Medo


2013-05-04 19:24:51 8 Comments

I am trying to make 4 dependent / cascading selection components. In this question, the selection component happens to be a <h:selectOneMenu>, but this is of course applicable on any other kind of selection component, such as <h:selectManyCheckbox>, <p:selectCheckboxMenu>, etc.

When the user chooses an item from the first menu, the second menu will show dependent data and when the user chooses item from the second one , the third one will show dependent data and so on.

The user will see items on the first menu only and the other ones will be blank. If he chooses an item on the first menu the second one will show data but the third and the fourth will remain blank, and so on. The user must eventually choose entries from all the 4 menus.

<h:selectOneMenu id="first" value="#{nodes.selectState"}>
    <f:selectItems value="#{nodes.stateList}"/>
    <f:ajax render="second">
</h:selectOneMenu>
<h:selectOneMenu id="second" value="#{nodes.selectCity"}>
    <f:selectItems value="#{nodes.cityList}"/>
    <f:ajax render="third">
</h:selectOneMenu>
<h:selectOneMenu id="third" value="#{nodes.selectRegion"}>
    <f:selectItems value="#{nodes.regionList}"/>
    <f:ajax render="fourth">
</h:selectOneMenu>
<h:selectOneMenu id="fourth" value="#{nodes.selectStation"}>
    <f:selectItems value="#{nodes.stationList}"/>
</h:selectOneMenu>

Nodes bean

private String selectState; //+setters, getters
private String selectCity; //+setters, getters
private String selectRegion; //+setters, getters
private String selectStation; //+setters, getters
private List<SelectItem> stateList; //+setters, getters
private List<SelectItem> cityList; //+setters, getters
private List<SelectItem> regionList; //+setters, getters
private List<SelectItem> stationList; //+setters, getters

public getStateList(){
    stateList= new ArrayList<SelectItem>();
    stateList.add(new SelectItem("A"));
}

public getCityList(){
    CityList= new ArrayList<SelectItem>();
    if(selectState.equals("A")){
        CityList.add(new SelectItem("B"));
    }
}

public getRegionList(){
    RegionList= new ArrayList<SelectItem>();
    if(selectCity.equals("B")){
        RegionList.add(new SelectItem("C"));
   }
}

public getStationList(){
    StationList= new ArrayList<SelectItem>();
    if(selectRegion.equals("C")){
        StationList.add(new SelectItem("D"));
    }
}

It's only working for the first 2 menus. The other 2 menus get null values.

4 comments

@BalusC 2013-05-06 11:22:42

Put the bean in the view scope and get rid of any business logic in getter methods.

The bean must be placed in the view scope so that all previous selections and new available items are remembered, otherwise things will fail when JSF needs to validate the selected item against the list of available items which was prepopulated in a previous selection, or when e.g. rendered attribute depends on a condition which was only set in a previous request.

The getter methods may not contain any business logic as they will also be invoked during among others the validations phase. You should use <f:ajax listener> to perform business logic based on a change. You should in the listener method also explicitly clear out selected values of child selection components. You can use <f:ajax render> to update the contents of child selection components.

Thus, so:

<h:selectOneMenu id="state" value="#{nodes.selectedState}">
    <f:selectItem itemValue="#{null}" itemLabel="-- select --" />
    <f:selectItems value="#{nodes.availableStates}" />
    <f:ajax listener="#{nodes.changeState}" render="city region station" />
</h:selectOneMenu>
<h:selectOneMenu id="city" value="#{nodes.selectedCity}">
    <f:selectItem itemValue="#{null}" itemLabel="-- select --" />
    <f:selectItems value="#{nodes.availableCities}" />
    <f:ajax listener="#{nodes.changeCity}" render="region station" />
</h:selectOneMenu>
<h:selectOneMenu id="region" value="#{nodes.selectedRegion}">
    <f:selectItem itemValue="#{null}" itemLabel="-- select --" />
    <f:selectItems value="#{nodes.availableRegions}" />
    <f:ajax listener="#{nodes.changeRegion}" render="station" />
</h:selectOneMenu>
<h:selectOneMenu id="station" value="#{nodes.selectedStation}">
    <f:selectItem itemValue="#{null}" itemLabel="-- select --" />
    <f:selectItems value="#{nodes.availableStations}" />
</h:selectOneMenu>

with

@Named
@ViewScoped
public class Nodes {

    private String selectedState; // getter+setter
    private String selectedCity; // getter+setter
    private String selectedRegion; // getter+setter
    private String selectedStation; // getter+setter
    private List<SelectItem> availableStates; // getter (no setter necessary!)
    private List<SelectItem> availableCities; // getter (no setter necessary!)
    private List<SelectItem> availableRegions; // getter (no setter necessary!)
    private List<SelectItem> availableStations; // getter (no setter necessary!)

    @EJB
    private SomeService someService;

    @PostConstruct
    public void init() {
        availableStates = someService.listStates();
    }

    public void changeState(AjaxBehaviorEvent event) {
        availableCities = someService.listCities(selectedState);
        selectedCity = selectedRegion = selectedStation = null;
        availableRegions = availableStations = null;
    }

    public void changeCity(AjaxBehaviorEvent event) {
        availableRegions = someService.listRegions(selectedCity);
        selectedRegion = selectedStation = null;
        availableStations = null;
    }

    public void changeRegion(AjaxBehaviorEvent event) {
        availableStations = someService.listStations(selectedRegion);
        selectedStation = null;
    }

    // Generate necessary getters+setters here. You should not change them.
}

See also:

@msgoon6 2016-03-26 07:09:56

You are facing this issue because you have twice id="first". Fix this and it should work.

@BalusC 2016-03-27 16:15:23

It's just a typo / copypaste mistake while preparing the question. If really the same ID was been used, OP would have faced an "IllegalArgumentException: duplicate component ID" already while just opening the page, not the problem as described by "it's only working at the first 2 menus the other 2 menus get null values"

@Archana 2013-05-07 09:26:16

There is a typo error in your code. For third menu you have given id name as "first" instead of "third". May be its because of that problem.

@newuser 2013-05-05 08:41:21

Try this, it may help you

By using the --Select City-- , --Select Region--, --Select Station-- to avoid the null pointer Exception.

    public getStateList(){
    stateList= new ArrayList<SelectItem>();
    stateList.add(new SelectItem("A"));
    }

    public getCityList(){
    CityList= new ArrayList<SelectItem>();
    if(selectState.equals("A"))
    {
      CityList.add(new SelectItem("B"));
    }
    else
    {
      CityList.add(new SelectItem("--Select City--"));
      selectCity = "--Select City--";
    }

    public getRegionList(){
    RegionList= new ArrayList<SelectItem>();
    if(selectCity.equals("B"))
    {
      RegionList.add(new SelectItem("C"));
    }
    else
    {
      RegionList.add(new SelectItem("--Select Region--"));
      selectRegion = "--Select Region--";
    }
    }

    public getStationList(){
    StationList= new ArrayList<SelectItem>();
    if(selectRegion.equals("C"))
    {
       StationList.add(new SelectItem("D"));
    }
    else
    {
      StationList.add(new SelectItem("Select Station"));
      selectStation = "--Select Station--";
    }
    }

@skuntsel 2013-05-05 09:02:40

If you attempt to answer you should provide for a textual explanation so that the readers and OP would be able to understand where the flaw in the code was and what exactly should be done to avoid the error.

@Shadooo Medo 2013-05-05 10:36:41

the problem is not in the java file. the problem is in the ajax rendering, the first menu is rendering the second but the second is not able to render the 3rd so the selectCity value doesn't reach the java code

Related Questions

Sponsored Content

9 Answered Questions

[SOLVED] Why JSF calls getters multiple times

1 Answered Questions

Map in f:selectItems for h:selectOneMenu breaks f:ajax

  • 2017-04-28 11:29:43
  • user1785730
  • 278 View
  • 1 Score
  • 1 Answer
  • Tags:   jsf

2 Answered Questions

[SOLVED] <h:selectOneMenu with conditional <f:selectItems shows options twice

  • 2016-08-08 18:29:41
  • Tom
  • 2052 View
  • 1 Score
  • 2 Answer
  • Tags:   jsf jsf-2.2

1 Answered Questions

JSF 2.2 dynamic h:selectOneMenu in p:dataTable submit old value

1 Answered Questions

[SOLVED] rendering values of multiple select boxes in a JSF form

1 Answered Questions

[SOLVED] Create dynamic ENUM Menu Tag in JSF 1.2

2 Answered Questions

[SOLVED] JSF/JAVA boolean switchers (private for JSF, public static for Beans)

  • 2011-05-28 20:06:44
  • gaffcz
  • 1151 View
  • 0 Score
  • 2 Answer
  • Tags:   java jsf richfaces

2 Answered Questions

[SOLVED] JSF: How to get the selected item from selectOneMenu if its rendering is dynamic?

  • 2010-05-19 07:43:22
  • Zmicier Zaleznicenka
  • 9373 View
  • 1 Score
  • 2 Answer
  • Tags:   jsf

2 Answered Questions

[SOLVED] Combining different javascript objects rendered by multiple components

  • 2008-10-12 22:37:25
  • royalghost
  • 588 View
  • 0 Score
  • 2 Answer
  • Tags:   javascript jsf

Sponsored Content