Question

I am trying to learn JSF 2, I have followed this tutorial which loads f:selecItems from java class method that return ArrayList. I tried to populate it using

f:selectItem itemValue="Row 1"

and it works. I look into the tutorial but I cannot see the difference so I do not know what I did wrong.

model:

@ManagedBean
@SessionScoped
public class LocationsAndActivities implements Serializable
{
    private final Location aLocations = new Location();
    private Activies aActivities = null;
    private String selectedLocation = "--- SELECT LOCATION ---";
    private String selectedActivity = "--- CHOOSE ACTIVITY ---";
    private boolean hasActivities = Boolean.FALSE;

    public ArrayList<SelectItem> getLocations()
    {
        return doGetLocations();
    }
    private ArrayList<SelectItem> doGetLocations()
    {
        final ArrayList<SelectItem> modifiedLoc = aLocations.getLocations();
        modifiedLoc.add(0, new SelectItem("--- SELECT LOCATION ---"));
        return modifiedLoc;
    }   

    public void setLocation(final String location)
    {
        doSetLocation(location);
    }
    private void doSetLocation(final String location)
    {
        this.selectedLocation = location;
        aActivities = new Activies(selectedLocation);
        hasActivities = aActivities.hasActivityLists();
    }

    public String getLocation()
    {
        return doGetLocation();
    }
    private String doGetLocation()
    {
        return this.selectedLocation;
    }

    public ArrayList<SelectItem> getActivities()
    {
        return doGetActivities();
    }
    private ArrayList<SelectItem> doGetActivities()
    {
        final ArrayList<SelectItem> returnValue;
        if(aActivities == null)
        {
            hasActivities = Boolean.FALSE;
            returnValue = new ArrayList<>();
        }
        else
        {
            returnValue = aActivities.getActivities();
        }
        returnValue.add(0,new SelectItem("--- CHOOSE ACTIVITY ---"));
        return returnValue;
    }

    public String getActivity()
    {
        return doGetActivity();
    }
    private String doGetActivity()
    {
        return this.selectedActivity;
    }

    public void setActivity(final String activity)
    {
        doSetActivity(activity);
    }
    private void doSetActivity(final String activity)
    {
        this.selectedActivity = activity;
    }

    public boolean isValidLocation()
    {
        return checkLocationValidity();
    }
    private boolean checkLocationValidity()
    {
        return hasActivities;
    }

    public String getMessage()
    {
        return doGetMessage();
    }
    private String doGetMessage()
    {
        return (hasActivities 
                ? "Please select location first" 
                        : "You select " + selectedLocation 
                        +" and activity of " + selectedActivity);
    }
}

view:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f= "http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>Title</title>
<link href="./css/styles.css" 
      rel="stylesheet" type="text/css"/> 
</h:head>
<h:body>

<h:form>
    Select Location of Adventure:
    <h:selectOneMenu value="#{locationAndActivities.location}">
        <f:selectItems value="#{locationAndActivities.locations()}"/>
        <f:ajax render="activityId" />
    </h:selectOneMenu><br />
    Select Location of Activities:
    <h:selectOneMenu id="activityId" 
                    value="#{locationAndActivities.activity}"
                    disabled="#{locationAndActivities.validLocation}">
        <f:selectItems value="#{locationAndActivities.activities()}"/> 
        <f:ajax render="messageId"/>
    </h:selectOneMenu><br />
    <h:outputText id="messageId" value="#{locationAndActivities.message}"/>
</h:form>
</h:body>
</html>

In one of the questions here about populating JSF combo box, I saw that one answers that I have to put @PostConstruct, I have tried it but still it does not load.

I hope someone could point what I did wrong..

Thanks

Was it helpful?

Solution

You are not using JSF expression in the correct way. #{locationAndActivities.locations()} will tell JSF to look for a method called locations() which you do not have in the bean. When using parentheses you need to use the full name of the method getLocations(). If you removed the parentheses JSF will look for a getter or a setter of that expression. e.g, locationAndActivities.location will look for either getLocation() method if it requires to returns an object, or setLocation(Location location) if it requires to set an object.

So instead of:

locationAndActivities.locations()

use:

locationAndActivities.locations

or

locationAndActivities.getLocations()

In addition, always avoid doing processes in bean getters and setters. The best practice is to populate the arraylist in the bean right after constructing it (@PostConstruct).

public class LocationsAndActivities implements Serializable
{
     private ArrayList<Location> locations;
     private Location location;

     @PostConstruct
     private void init(){
          //fill locations arraylist with data
     }


     public ArrayList<Location> getLocations(){
           return locations;
     }

     public Location getLocation(){
           return location;
     }

     public void setLocation(Location location){
           this.location = location;
     }
}

<h:selectOneMenu value="locationAndActivities.location">
    <f:selectItem itemLabel="---Select Location---"  noSelectionOption="true">
    <f:selectItems value="locationAndActivities.locations" var="var" itemValue="var">
</h:selectOneMenu>

Note: Due to HTML Structure, you need to use converter when passing selected Location objects to the bean. Converters are necessary for data types that are not of String types or not of those types that JSF has a built-in converter for (such as int, Integer, Long, long, Double, double... etc). Otherwise you need to use a converter to pass your object back to the bean.

See also:

SelectItem Wiki page

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top