agileai
agileai

Reputation: 211

Trouble with Primefaces 3.0.M2 SelectOneMenu Ajax behavior

I am having trouble with implementing two SelectOneMenu controls, where data in the second one depends on the selection made in the first. This example on the primeFaces showcase is almost the same as what I want to implement: http://www.primefaces.org/showcase-labs/ui/pprSelect.jsf

except that I have to get the data from a database.

The above example is working correctly in the same project. I am using NetBeans 7.0 with GlassFish 3.1 and PrimeFaces 3.0.M2, the latest drop (20th June 2011).

The source code of the JSF page and the managed bean is attached.

<?xml version='1.0' encoding='UTF-8' ?>
<!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:h="http://java.sun.com/jsf/html"
  xmlns:p="http://primefaces.prime.com.tr/ui" 
  xmlns:f="http://java.sun.com/jsf/core">
<h:head><title>Facelet Title</title></h:head>
<h:body>
 <p:log />
    <center>
        <h:form>
            <h:outputText value="State: "/>
            <p:selectOneMenu id="selectState" value="#{stateCityBean.selectedStateArray}">
                <f:selectItem itemLabel="Select Any" itemValue="Empty String"/>
                <p:ajax update="selectCity" listener="#{stateCityBean.updateCityMap}"/>
                <f:selectItems value="#{stateCityBean.stateMap}" />
            </p:selectOneMenu>
            <p></p>
            <h:outputText value="City: "/>
            <p:selectOneMenu id="selectCity" value="#{stateCityBean.selectedCityArray}">
                <f:selectItem itemLabel="Select Any" itemValue="Empty String"/>
                <f:selectItems value="#{stateCityBean.cityMap}"/>
            </p:selectOneMenu>
        </h:form>
    </center>
</h:body>

StateCityBean.java

package com.xyz.mbeans;
import com.iwizability.priceinfo.dao.*;
import com.iwizability.priceinfo.pojo.*;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.context.Flash;
import javax.faces.event.ValueChangeEvent;

@ManagedBean
@SessionScoped
public class StateCityBean {
private String selectedStateArray;
private Map<String, State> StateMap;
private Map<String, City> CityMap;
private String selectedCityArray;

public StateCityBean() {
    System.out.println("Inside.............. ");
    StateMap = new LinkedHashMap<String, State>();
    CityMap = new LinkedHashMap<String, City>();
}

public String getSelectedStateArray() {return selectedStateArray;}

public void setSelectedStateArray(String selectedStateArray) {this.selectedStateArray = selectedStateArray;}

public Map<String, State> getStateMap() {
    StateDaoImpl stateObj = new StateDaoImpl();
    StateMap = stateObj.getState();
    return StateMap;
}

public void setStateMap(Map<String, State> stateArray) {this.StateMap = stateArray;}

public String getSelectedCityArray() {return selectedCityArray;}

public void setSelectedCityArray(String selectedCityArray) {this.selectedCityArray = selectedCityArray;}

public Map<String, City> getCityMap() {
    CityDaoImpl cityObj = new CityDaoImpl();
    int stateId = 0;
    if (selectedStateArray != null && !selectedStateArray.equals("")) {
        stateId = StateMap.get(selectedStateArray).getId();
    }
    CityMap = cityObj.getCity(stateId);
    return CityMap;
}

public void setCityMap(Map<String, City> CityArray) {
    this.CityMap = CityArray;
}

public void updateCityMap() {
    CityDaoImpl cityObj = new CityDaoImpl();
    int stateId = 0;
    if (selectedStateArray != null && !selectedStateArray.equals("")) {
        stateId = StateMap.get(selectedStateArray).getId();
        this.CityMap = cityObj.getCity(stateId);
    }
 }

}

On debugging, I can see that the updateCityMap method is invoked but the SelectedStateArray variable is null. Even force changing the value of bound CityMap variable does not update the selectCity drop down.

As you would have guessed, I am new to JSF, but the problem is compounded by the fact that I am using a still in development version of the tag library...

Upvotes: 21

Views: 16922

Answers (6)

halil
halil

Reputation: 1812

you should just add

event="change"

to p:ajax

Upvotes: 0

John Yeary
John Yeary

Reputation: 1113

I created a demo for the exact same situation you describe in your project. I have a state and city <p:selectOneMenu/> elements on my page. You select a state, and the cities update. If a different state is selected, the city is erased since it may not exist in the state.

The difference is that I use <p:ajax event="change" update="cities, cs"/> to update the elements, and an actionListener to update the city if the state is different.

<p:selectOneMenu id="states" value="#{dataBean.selectedState}"
   valueChangeListener="#{dataBean.stateChangeListener(event)}"
   style="width: 150px;">
   <f:selectItem itemLabel="" itemValue=""/>
   <f:selectItems value="#{dataBean.states}"/>
   <p:ajax event="change" update="cities, cs"/>
</p:selectOneMenu>
<h:outputLabel value="City:" for="cities"/>
<p:selectOneMenu id="cities" 
   value="#{dataBean.selectedCity}" 
   style="width: 150px;">
   <f:selectItem itemLabel="" itemValue=""/>
   <f:selectItems value="#{dataBean.cities}"/>
   <p:ajax event="change" update="cs" />
 </p:selectOneMenu>

The whole project and demo code can be found on my blog. I saw this post and decided to post my project. [blog]: http://javaevangelist.blogspot.com/2012/07/primefaces-ajax-enabled.html

Upvotes: 2

djmj
djmj

Reputation: 5544

Maybe its the primefaces version but your update method in your bean looks pretty complicated.

Why not retrieve the Object of the selection from the ajax event?, this way you don't need to define that variable.

public void update(AjaxBehaviorEvent event)
{
    Object selectOneMenuObject = ((UIOutput)event.getSource()).getValue();

    //String selectedStateArray = (String)((UIOutput)event...
    //update temporary collection of second SelectOneMenu
}

Don't know if that will help you, but thats just the way I do it.

Upvotes: 0

Mustafa SAHIN AYDIN
Mustafa SAHIN AYDIN

Reputation: 329

Primefaces is trying something diffent. I dont know why. First of all you must know these releases are not stable. When you analys code with firebug you will shove this. Lets assume two combo who has ids countries and cities when you changed the first combo cities update correcty but cities combo' id change to cities_input they add _input prefix. When I analys primefaces source code. Thereare codes something like traverse tree if visited change id by adding _input or _panel. So if you change the combo in second time. Everything work perfect except you said update cities but there is no component who has id cities becouse it has new id cities_input. So your ajax does not work correctly. But they correct this bug in 3.0m4 or after releases.

This is the problem. Another example of this problem it is bug someone open jira for this. İf you are using login with spring security j_username, j_password change to j_username_input j_password_input. So this breaks the standart and code does not work in second ajax requests. Hope this helps..

pay attention to lionhearts words. Primefaces namespaces changed in 3.m4 in pages use this. xmlns:p="http://primefaces.org/ui"

Upvotes: 1

lionheart
lionheart

Reputation: 177

I use PrimeFaces 3.0.M4 with namespaces:

<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:p="http://primefaces.org/ui">

It seems to work fine.

Upvotes: 0

islon
islon

Reputation: 1207

I did a state -> city select in my jsf project the same way you did. The only differences I found are:

  • my p:ajax has a change event: <p:ajax event="change" update="city" listener="#{contatoMB.filterCities}" />.
  • my p:ajax comes last after the f:selectItems but this shouldn't be the problem.
  • my f:selectItems list in the city select is List<javax.faces.model.SelectItem> and not a Map<String, City>, have you tried using SelectItems instead of your map?
  • my form has an id and prependId false <h:form id="contact-form" prependId="false">, again, this shouldn't be the problem.
  • my h:selectOneMenu is inside a p:panel, some PrimeFaces components behave in a strange way when inside or outside some other components.

If none of this works maybe the problem is the PrimeFaces version you're using. My PrimeFaces version is 2.2.1.

Upvotes: 0

Related Questions