Trouble with Primefaces 3.0.M2 SelectOneMenu Ajax behavior
Asked Answered
H

6

21

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...

Hepplewhite answered 22/6, 2011 at 5:49 Comment(11)
This may only be part of your issue but your update attribute is referring directly to your city drop down component by id update="selectCity". The problem with this is that in JSF the <h:form> will prepend its id to child elements by default. Try specifying the following attribute to your <h:form> and see if that fixes your problem, prependId="false"Boigie
@maple_shaft: This is the way the update attribute is used in all examples I've seen... I tried disabling prependId but it doesn't seem to solve the problem.Hepplewhite
So, I added a event="valueChange" attribute to p:ajax and am now getting an error: j_idt8:selectState: Validation Error: Value is not valid On looking up the Validation Error, it seems the web is full of this problem. With JSF in general and also with PrimeFaces specifically: primefaces.prime.com.tr/forum/viewtopic.php?f=3&t=6947 java.net/blogs/lamine_ba coderanch.com/t/501774/JSF/java/… I tried changing the scope to viewscoped, however, that's not doing the trick for me either...Hepplewhite
Wow, thats an odd problem! I saw it mentioned in one of these threads to try overriding equals and hashCode. Did you try this? It seems like that fixes this for some people. If that didn't work for you I am willing to post a bounty on this question.Boigie
thanks maple! i am totally lost right now... don't understand how this code (primefaces.org/showcase-labs/ui/pprSelect.jsf) is working properly in the same projectHepplewhite
what's not clear to me is: 1. do we need to implement equals and hashCode always with selectOneMenu? 2. do we need to implement a convertor and a validator? Always? Or under some conditions? While there are enough rersources on the web that discuss how to implement each of these, they don't explain under what condition they would be required...Hepplewhite
It's no surprise that we don't find too many people JSF developers either. I looked at sites like Odesk and Elance. For JSF, there are 840 providers on Elance and 1073 on Odesk. And for jsf primefaces only 15 on odesk and 5 on elance... On the other hand there 142 for play framework on odesk, and 460 on elance. Seems like JSF is fighting a losing battle.Hepplewhite
btw- asp.net has 20,675 on odesk and 19,809 on elance. I am not marketing anything... just venting my frustration at not being able to implement something simple in JSF even though i would prefer to use the java stack for production...Hepplewhite
2nd-3rd comment: I used to be an ASP.NET developer, TRUST ME that ASP.NET suffers MANY of the same types of problems. JSF is a better technology. I admit that JSF 1.2 has some issues, however JSF 2.0 made HUGE improvements and every day the JSF component suites and implementations improve in features and quality. Remember that ASP.NET has been around for a LOT longer than JSF 2.0, it is still a relatively new technology. I understand your frustration believe me. There are still enough issues with JSF that I don't feel a project would be successful under strict UI and design requirements.Boigie
@agileai: Not related to the problem, but you are not following the Java Bean naming convention properly. Usually the first letter in property name is small and it's capitalised in its getter/setter.Savitt
When you are using Map equals and hashCode is necessary for the key and in this case since you are using String for key, you don't need to do that because it's already done in the String class.Savitt
A
2

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

Alonso answered 5/7, 2012 at 21:18 Comment(0)
T
1

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"

Trove answered 12/1, 2012 at 9:48 Comment(0)
O
0

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.

Osteopathy answered 1/9, 2011 at 17:24 Comment(0)
R
0

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.

Redouble answered 1/12, 2011 at 11:0 Comment(0)
A
0

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.

Amblyopia answered 13/2, 2012 at 3:20 Comment(0)
L
0

you should just add

event="change"

to p:ajax

Larkspur answered 6/7, 2012 at 6:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.