Primefaces 3.0.M2 SelectOneMenu Ajax行为出现问题

21
我在实现两个SelectOneMenu控件时遇到了麻烦,第二个控件中的数据取决于第一个控件的选择。这个例子在primeFaces展示页面上几乎与我要实现的相同:http://www.primefaces.org/showcase-labs/ui/pprSelect.jsf,除了我必须从数据库中获取数据。上面的示例在同一项目中工作正常。我使用的是NetBeans 7.0和GlassFish 3.1以及PrimeFaces 3.0.M2(最新版本为2011年6月20日)。JSF页面和托管bean的源代码已附上。
<?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);
    }
 }

在调试时,我可以看到updateCityMap方法被调用,但SelectedStateArray变量为null。即使强制更改绑定的CityMap变量的值,也不会更新selectCity下拉列表。

正如你所猜测的那样,我对JSF还很陌生,但问题的复杂性还增加了一个事实,那就是我正在使用仍处于开发中版本的标签库...


这可能只是你问题的一部分,但你的更新属性直接通过id“update =”selectCity“”引用了你的城市下拉组件。问题在于,在JSF中,<h:form>默认会将其ID前缀添加到子元素。尝试将以下属性指定给你的<h:form>,看看是否可以解决你的问题,“prependId =”false“”。 - maple_shaft
1
@maple_shaft:这是我看到的所有示例中使用更新属性的方式...我尝试禁用prependId,但似乎并没有解决问题。 - agileai
所以,我在p:ajax中添加了event="valueChange"属性,现在出现了一个错误:j_idt8:selectState: 验证错误:值无效。查看验证错误,似乎网络上充斥着这个问题。无论是在JSF一般还是在PrimeFaces中都是如此: http://primefaces.prime.com.tr/forum/viewtopic.php?f=3&t=6947 http://www.java.net/blogs/lamine_ba http://www.coderanch.com/t/501774/JSF/java/JSF-PrimeFace-Validation-Error-Value 我尝试将作用域(scope)更改为视图作用域(viewscoped),但对我来说也行不通... - agileai
1
哇,这是个奇怪的问题!我在其中一个帖子中看到有人建议尝试重写equals和hashCode方法。你试过吗?似乎这对一些人来说可以解决这个问题。如果这对你没用的话,我愿意在这个问题上发布悬赏。 - maple_shaft
我们并不惊讶JSF开发者的数量不多。我查看了像Odesk和Elance这样的网站。对于JSF,在Elance上有840个提供者,在Odesk上有1073个。而对于仅限于jsf primefaces,Odesk上只有15个,Elance上只有5个...另一方面,在Odesk上有142个play框架的提供者,在Elance上有460个。看起来JSF正在进行一场失败的战斗。 - agileai
显示剩余6条评论
6个回答

2
我在您的项目中创建了一个演示文稿,涉及与您所描述的完全相同的情况。在我的页面上,有一个状态和城市<p:selectOneMenu/>元素。您选择一个州,城市就会更新。如果选择了另一个州,则城市将被删除,因为它可能不存在于该州。
不同之处在于我使用<p:ajax event="change" update="cities, cs"/>来更新元素,并使用actionListener来更新城市(如果州不同)。
<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>

整个项目和演示代码可以在我的博客上找到。我看到这篇文章,决定发布我的项目。[博客]: http://javaevangelist.blogspot.com/2012/07/primefaces-ajax-enabled.html


1

Primefaces正在尝试一些不同的东西。我不知道为什么。首先,您必须知道这些版本不稳定。 当您使用firebug分析代码时,您将推开这个问题。 假设有两个组合框,它们的ID分别为countries和cities 当您更改第一个组合框时,城市正确更新,但城市组合框的ID更改为cities_input,它们添加了_input前缀。当我分析primefaces源代码时,有一些代码类似于遍历树,如果访问过,则通过添加_input或_panel更改id。因此,如果您第二次更改组合框,则除了您说的更新城市之外,一切都完美,但是没有具有城市ID的组件,因为它具有新的ID cities_input。因此,您的ajax无法正常工作。但是他们在3.0m4或之后的版本中纠正了这个错误。

这就是问题所在。这个问题的另一个例子是有人为此打开了jira的错误报告。 如果您正在使用Spring Security登录j_username、j_password,则更改为j_username_input j_password_input。因此,这会破坏标准,并且代码在第二个ajax请求中无法正常工作。 希望这可以帮助到您。

请注意Lionhearts的话。Primefaces命名空间在3.m4中更改,请在页面中使用此命名空间。 xmlns:p="http://primefaces.org/ui"


0
也许是因为 primefaces 版本的原因,但是你在 bean 中的更新方法看起来相当复杂。
为什么不从 ajax 事件中检索选择的对象呢?这样你就不需要定义那个变量了。
public void update(AjaxBehaviorEvent event)
{
    Object selectOneMenuObject = ((UIOutput)event.getSource()).getValue();

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

不知道这是否对你有帮助,但这就是我做的方式。


0

我使用带有命名空间的PrimeFaces 3.0.M4:

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

看起来运行良好。


0

我在我的JSF项目中使用了与您相同的方法进行了状态 -> 城市选择。 我发现的唯一区别是:

  • 我的p:ajax具有change事件:<p:ajax event="change" update="city" listener="#{contatoMB.filterCities}" />
  • 我的p:ajaxf:selectItems之后,但这不应该是问题。
  • 我的城市选择中的f:selectItems列表是List<javax.faces.model.SelectItem>而不是Map<String,City>,您是否尝试过使用SelectItem而不是您的映射?
  • 我的表单具有ID和prependId false <h:form id="contact-form" prependId="false">,同样,这不应该是问题。
  • 我的h:selectOneMenu位于p:panel内部,某些PrimeFaces组件在其他某些组件内部或外部时会表现出奇怪的方式。
如果以上方法都无效,可能问题出在您使用的PrimeFaces版本。我的PrimeFaces版本是2.2.1。

0

你只需要添加

event="change"

转换为 p:ajax


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接