3

I want to create JSF registration form which has select menu with the list of all countries. I know that this is easy for implementation with Java HashMap but the tricky part that I don't know how to implement is how right after the user selects his country from the list, second select menu to appear with the cities in his country? Is there any useful example?

Best wishes.

BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
user1285928
  • 2,380
  • 25
  • 87
  • 142

1 Answers1

14

You can use <f:ajax> for this. When nested in an input component such as <h:selectOneMenu>, then it will by default be invoked when the input value is changed. You can specify a listener method which could prepopulate the data for the next component based on the current input value, and you can specify the client ID of that next component in render in order to show the prepopulated data.

<h:selectOneMenu value="#{bean.country}">
    <f:selectItems value="#{bean.countries}" />
    <f:ajax listener="#{bean.changeCountry}" render="cities" />
</h:selectOneMenu>
<h:panelGroup id="cities">
    <h:selectOneMenu value="#{bean.city}" rendered="#{not empty bean.cities}">
        <f:selectItems value="#{bean.cities}" />
    </h:selectOneMenu>
</h:panelGroup>

The bean must be in at least the view scope (not request):

@ManagedBean
@ViewScoped
public class Bean implements Serializable {

    private String country; // +getter+setter
    private String city; // +getter+setter
    private List<String> countries; // +getter
    private List<String> cities; // +getter

    @EJB
    private LocationService locationService;

    @PostConstruct
    public void init() {
        countries = locationService.getCountries();
    }

    public void changeCountry() {
        cities = locationService.getCities(country);
    }

    // ...
}

You can of course also use a Map<String, String> instead of a List<String>. The map key becomes the option label and the map value becomes the option value. You only need to keep in mind that a HashMap is by nature unordered. You'd prefer using LinkedHashMap instead to display the items in Map insertion order.

See also:

Community
  • 1
  • 1
BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
  • +1 for @BalusC, the answer is very clear enough and [your blog](http://balusc.blogspot.in/2007/10/populate-child-menus.html) explains it much more deep. :) What if i have 100 users accessing the same page, i'm wasting the memory by creating 100 different objects! Is there a way to optimize so that we can use the Object at Application Level. – 09Q71AO534 Apr 18 '15 at 06:36
  • @09Q71AO534: just put application scoped data like `#{bean.countries}` in an application scoped bean and make use of JPA 2nd level cache for the cities. – BalusC Apr 20 '15 at 07:31
  • @BalusC Do you know which Java package I need to insert for `private LocationService locationService;`? – Peter Penzov Mar 11 '16 at 13:37
  • @Peter: It's just your own service class. Name was just exemplary like `Bean` – BalusC Mar 11 '16 at 13:46
  • @BalusC Is it possible to change the 2nd dropdown without actually submitting (and setting) the 1st one? (by using execute="@none"). If my form is inside a popup which can be closed/cancelled, I don't want any change of the 1st (ajax) dropdown to be applied to my model until the "save" submit button is used. – Xavier Dury Apr 17 '18 at 07:57