2

I have written a program using jsf 1.2 . In this program a user needs to select his country, state, and city. When he selects a country, he must see the list of states in it in a dropdown & when he selects a state, he must see the cities in it in a dropdown.

For that I have created 2 classes, 1 inner class , and one jsf page.

When I select a country , I can see a dropdown for state is immediately shown.

Problem is when a state is changed, the drop down for city is not immediately seen. Only after 2nd change in state, the drop down for cities is seen.

(Note: I cannot remove the method cityChangeListener() in this code , as i need to generate an id using country-code,state-code,city-code,and a random number. )

Any help would be highly appreciated.

Here is my code (4 files):

file: faces-config.xml

<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="1.2" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
    <managed-bean>
        <managed-bean-name>formBackingBean</managed-bean-name>
        <managed-bean-class>FormBackingBean</managed-bean-class>
        <managed-bean-scope>session</managed-bean-scope></managed-bean>
</faces-config>

file: newjsf.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
<%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%>
<f:view>
    <h:form>
        <h:inputText
            id="input"
            value="#{formBackingBean.input}"
            immediate="true"
            disabled="true"
            />
        <br/>
        <h:selectOneMenu
            id="country"
            value="#{formBackingBean.country}"
            valueChangeListener="#{formBackingBean.countryChangeListener}"
            immediate="true"
            onchange="submit();"
            >
            <f:selectItems
                id="countries"
                value="#{formBackingBean.countries}"
                />
        </h:selectOneMenu>
        <br/>
        <h:selectOneMenu
            id="state"
            value="#{formBackingBean.state}"
            valueChangeListener="#{formBackingBean.stateChangeListener}"
            immediate="true"
            onchange="submit();"
            rendered="#{formBackingBean.states!=null}"
            >
            <f:selectItems
                id="states"
                value="#{formBackingBean.states}"
                />
        </h:selectOneMenu>
        <br/>
        <h:selectOneMenu
            id="city"
            value="#{formBackingBean.city}"
            immediate="true"
            onchange="submit();"
            rendered="#{formBackingBean.cities!=null}"
            valueChangeListener="#{formBackingBean.cityChangeListener}"
            >
            <f:selectItems
                id="cities"
                value="#{formBackingBean.cities}"
                />
        </h:selectOneMenu>
    </h:form>
</f:view>

file: FormBackingBean.java

import java.util.List;
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;

public class FormBackingBean {

    private String input;
    private String country;
    private String state;
    private String city;
    private List<SelectItem>countries=GeoMapLister.WORLD.getNamesOfPlacesWithin();//MapLister.countryList;
    private List<SelectItem>states=null;
    private List<SelectItem>cities=null;
    public FormBackingBean() {
    }

    public String getCity() {
        return city;
    }

    public String getCountry() {
        return country;
    }

    public String getState() {
        return state;
    }

    public void setCity(String city) {
        this.city = city;
        FacesContext.getCurrentInstance().renderResponse();
    }

    public void setCountry(String country) {
        this.country = country;
        FacesContext.getCurrentInstance().renderResponse();
    }

    public void setState(String state) {
        this.state = state;
    }

    public List<SelectItem> getCities() {
        return cities;
    }

    public List<SelectItem> getCountries() {
        return countries;
    }

    public List<SelectItem> getStates() {
        return states;
    }

    public void setCities(List<SelectItem> cities) {
        this.cities = cities;
    }

    public void setCountries(List<SelectItem> countries) {
        this.countries = countries;
    }

    public void setStates(List<SelectItem> states) {
        this.states = states;
    }

    public String getInput() {
        return input;
    }

    public void setInput(String input) {
        this.input = input;
    }

    public void countryChangeListener(final ValueChangeEvent valueChangeEvent){
        input=valueChangeEvent.getNewValue().toString();
        states=GeoMapLister.WORLD.getPlacesWithin().get(input).getNamesOfPlacesWithin();
        state=null;
        cities=null;
        city=null;
        FacesContext.getCurrentInstance().renderResponse();
    }
    public void stateChangeListener(final ValueChangeEvent valueChangeEvent){
        input=valueChangeEvent.getNewValue().toString();
        cities=GeoMapLister.WORLD.getPlacesWithin()
                .get(country).getPlacesWithin().get(input)
                .getNamesOfPlacesWithin();
        city=null;
        FacesContext.getCurrentInstance().renderResponse();
    }
    public void cityChangeListener(final ValueChangeEvent valueChangeEvent){
        input=valueChangeEvent.getNewValue().toString();
        FacesContext.getCurrentInstance().renderResponse();
    }
}

file: GeoMapLister.java

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.faces.model.SelectItem;

public class GeoMapLister {
    public static class GeographicalLocation{
        private final GeographicalLocation parent;
        private final String code;
        private final String name;
        private final List<SelectItem>namesOfPlacesWithin;
        private final HashMap<String,GeographicalLocation>placesWithin;

        public GeographicalLocation(GeographicalLocation parent,String code, String name,boolean leaf) {
            this.parent = parent;
            this.name = name;
            this.code= code;
            ArrayList<SelectItem> namesofplaceswithin = null;
            HashMap<String,GeographicalLocation> placeswithin = null;
            if(!leaf){
                namesofplaceswithin = new ArrayList<SelectItem>();
                namesofplaceswithin.add(new SelectItem(null, "- select -"));
                placeswithin = new HashMap<String,GeographicalLocation>();
                placeswithin.put(null, null);
            }
            this.namesOfPlacesWithin = namesofplaceswithin;
            this.placesWithin = placeswithin;
        }

        public String getName() {
            return name;
        }

        public GeographicalLocation getParent() {
            return parent;
        }

        public List<SelectItem> getNamesOfPlacesWithin() {
            return namesOfPlacesWithin;
        }

        public String getCode() {
            return code;
        }

        public GeographicalLocation addPlaceWithin(String code,String name,boolean leaf){
            GeographicalLocation newGeographicalLocation = new GeographicalLocation(this, code,name,leaf);
            placesWithin.put(code,newGeographicalLocation);
            namesOfPlacesWithin.add(new SelectItem(code, name));
            return newGeographicalLocation;
        }

        public HashMap<String, GeographicalLocation> getPlacesWithin() {
            return placesWithin;
        }

        List<SelectItem> getPlacesWithin(String input) {
            return placesWithin.get(input).namesOfPlacesWithin;
        }

    }

    public static final GeographicalLocation WORLD=new GeographicalLocation(null, "WORLD","WORLD",false);

    static
    {
        GeographicalLocation IN = WORLD.addPlaceWithin("IN", "India", false);
        GeographicalLocation MH = IN.addPlaceWithin("MH", "Maharashtra", false);
        MH.addPlaceWithin("MU", "Mumbai", true);
        MH.addPlaceWithin("PU", "Pune", true);
        MH.addPlaceWithin("NA", "Nashik", true);
        GeographicalLocation KA = IN.addPlaceWithin("KA", "Karnataka", false);
        KA.addPlaceWithin("BA", "Bangalore", true);
        KA.addPlaceWithin("MA", "Mangalore", true);
        GeographicalLocation BE = IN.addPlaceWithin("BE", "West Bengal", false);
        BE.addPlaceWithin("KO", "Kolkata", true);
        BE.addPlaceWithin("KH", "Kharagpur", true);

        //--------------
        GeographicalLocation UK = WORLD.addPlaceWithin("UK", "U.K.", false);
        GeographicalLocation YO = UK.addPlaceWithin("YO", "York", false);
        YO.addPlaceWithin("SS", "Sussex", true);
        YO.addPlaceWithin("MS", "Middlesex", true);

        //--------------
        GeographicalLocation US = WORLD.addPlaceWithin("US", "U.S.A.", false);
        GeographicalLocation NY = US.addPlaceWithin("NY", "New York", false);
        NY.addPlaceWithin("NC", "New York city", true);
        NY.addPlaceWithin("NU", "New York urban", true);
        GeographicalLocation CA = US.addPlaceWithin("CA", "California", false);
        CA.addPlaceWithin("WA", "Washington, district of California", true);
        CA.addPlaceWithin("SI", "Silicon Valley", true);
        CA.addPlaceWithin("VS", "Very-Silly-Con Valley", true);

    }
}
Abhishek Oza
  • 3,340
  • 1
  • 27
  • 35

1 Answers1

0

Have you tried to read here? There is an example that works with child menus.

Tudor Zgureanu
  • 725
  • 7
  • 11
  • Thanks for the link. I got a chance to look deeper into the JSF life-cycle. Now the following modification solved the issue: `public void countryChangeListener(final ValueChangeEvent valueChangeEvent){` `country=valueChangeEvent.getNewValue().toString();` `.` `.` `public void stateChangeListener(final ValueChangeEvent valueChangeEvent){` `state=valueChangeEvent.getNewValue().toString();` `.` `.` `public void cityChangeListener(final ValueChangeEvent valueChangeEvent){` `city=valueChangeEvent.getNewValue().toString();` – Abhishek Oza Mar 28 '13 at 08:44