Jsf 2 primefaces p:对话框表单提交在ui内时不调用复合组件设置器:重复
编辑:问题是当复合组件被包装在ui:repeat或h:datatable中以及p:dialog中时 在p:对话框中使用复合组件提交表单时,我似乎遇到了问题 普通p:boolean和类似字段上的setter被调用,但复合组件中的setter不是,尽管getSubmittedvalue是 初始值为null,并且当不在模式p:dialog中时,相同的东西也可以工作 我可以在调试/配置文件模式下清楚地看到它Jsf 2 primefaces p:对话框表单提交在ui内时不调用复合组件设置器:重复,jsf-2,primefaces,composite-component,Jsf 2,Primefaces,Composite Component,编辑:问题是当复合组件被包装在ui:repeat或h:datatable中以及p:dialog中时 在p:对话框中使用复合组件提交表单时,我似乎遇到了问题 普通p:boolean和类似字段上的setter被调用,但复合组件中的setter不是,尽管getSubmittedvalue是 初始值为null,并且当不在模式p:dialog中时,相同的东西也可以工作 我可以在调试/配置文件模式下清楚地看到它 INFO: Initializing Mojarra 2.1.6 (SNAPSHOT 20111
INFO: Initializing Mojarra 2.1.6 (SNAPSHOT 20111206) for context '/webclient'
INFO: Running on PrimeFaces 3.5
INFO: Running on PrimeFaces Extensions 0.6.3
编辑:也尝试将初始值设置为默认值,即不为空。同样的事情也会发生……二传手不会接到电话
我必须再次强调,当不在p:dialog with appendtobody true中时,同样的事情也会发生,如果这很重要的话
SSCCE
控制器:
@ManagedBean
@ViewScoped
public class TestController implements Serializable {
List<TestSelect> testbeanList;
List<BeanObject> beanList;
@PostConstruct
void init() {
testbeanList = new ArrayList<TestSelect>() {
{
add(new TestSelect("km"));
add(new TestSelect("g"));
add(new TestSelect("lbs"));
}
};
beanList = new ArrayList<BeanObject>() {
{
add(new BeanObject(2.0d, "lbs"));
add(new BeanObject(3.0d, "g"));
add(new BeanObject(4.0d, "km"));
}
};
}
public List<TestSelect> getTestbeanList() {
return testbeanList;
}
public void setTestbeanList(List<TestSelect> testbeanList) {
this.testbeanList = testbeanList;
}
public BeanObject getBeanObject() {
return BeanObject;
}
public void setBeanObject(BeanObject BeanObject) {
this.BeanObject = BeanObject;
}
}
Facelet:
<!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:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:pe="http://primefaces.org/ui/extensions"
>
<h:head>
</h:head>
<h:body>
<p:dialog widgetVar="dlg" appendToBody="true">
<h:form>
<ui:repeat var="uom" value="#{testController.beanList}">
<usb:uom value="#{uom}" list="#{testController.testBeanList}"/>
</ui:repeat>
<p:commandButton process="@form" action="null" value="submit" />
</h:form>
</p:dialog>
<h:form>
<p:commandButton onclick="dlg.show();" value="show dlg" />
</h:form>
</h:body>
</html>
解决方案是以下几方面的结合: 使用c:forEach而不是ui-repeat我知道这在jsf2中应该是不好的做法 将@SessionScoped注释用于表单备份beans控制器
听起来很奇怪,这两件事让问题消失了。目前:观察:当复合组件位于循环组件(如ui:repeat或h:datatable)之外时,会调用p:dialog setter内部。在iterable组件和对话框中,是什么阻止了setter被调用?是否有任何特定的东西阻止自定义复合组件在p:dialog中提交?有人能帮忙吗?c:forEach很管用..这不是一种糟糕的做法吗?
<!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:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:pe="http://primefaces.org/ui/extensions"
>
<h:head>
</h:head>
<h:body>
<p:dialog widgetVar="dlg" appendToBody="true">
<h:form>
<ui:repeat var="uom" value="#{testController.beanList}">
<usb:uom value="#{uom}" list="#{testController.testBeanList}"/>
</ui:repeat>
<p:commandButton process="@form" action="null" value="submit" />
</h:form>
</p:dialog>
<h:form>
<p:commandButton onclick="dlg.show();" value="show dlg" />
</h:form>
</h:body>
</html>
/** The Constant LOGGER. */
private static final Logger LOGGER = Logger.getLogger(TestComponent.class);
// Fields
// -------------------------------------------------------------------------------------
/** The measure. */
private UIInput measure;
/** The unit. */
private UISelectOne unit;
// Actions
// ------------------------------------------------------------------------------------
/*
* (non-Javadoc)
*
* @see javax.faces.component.UIInput#getFamily()
*/
/**
* Gets the family.
*
* @return the family
*/
@Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
/*
* (non-Javadoc)
*
* @see
* javax.faces.component.UIComponent#encodeAll(javax.faces.context.FacesContext
* )
*/
/**
* Encode all.
*
* @param context
* the context
* @throws IOException
* Signals that an I/O exception has occurred.
*/
@Override
public void encodeBegin(FacesContext context) throws IOException {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("encodeAll BEGIN");
}
Object testTest = getAttributeValue("value", "");
String val = null;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("testTest -> " + testTest.toString());
}
if (testTest instanceof BeanObject) {
val = testTest.toString();
} else {
val = (String) testTest;
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("val -> " + val);
}
if (!val.equals("")) {
String[] testSplitted = val.split(" ");
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("testSplitted -> " + testSplitted);
for (int i = 0; i < testSplitted.length; i++) {
LOGGER.debug("testSplitted it -> " + testSplitted[i]);
}
}
measure.setValue(testSplitted[0]);
unit.setValue(testSplitted[1]);
}
super.encodeBegin(context);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("encodeAll END");
}
}
/**
* Gets the converted value.
*
* @param context
* the context
* @param submittedValue
* the submitted value
* @return the converted value
*/
@Override
protected Object getConvertedValue(FacesContext context, Object submittedValue) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("getConvertedValue()");
}
String[] tmpVal = ((String) getSubmittedValue()).split(" ");
if (LOGGER.isDebugEnabled()) {
for (int i = 0; i < tmpVal.length; i++) {
LOGGER.debug("unit and val -> " + i + " -> " + tmpVal[i]);
}
}
if (tmpVal == null || Strings.isNullOrEmpty(tmpVal[0])) {
return null;
}
BeanObject test = new BeanObject(Double.parseDouble(tmpVal[0]), tmpVal[1]);
return test;
}
/*
* (non-Javadoc)
*
* @see javax.faces.component.UIInput#getSubmittedValue()
*/
/**
* Gets the submitted value.
*
* @return the submitted value
*/
@Override
public Object getSubmittedValue() {
if (Strings.isNullOrEmpty((String) getMeasure().getValue())) {
return null;
}
if (Strings.isNullOrEmpty((String) getUnit().getValue())) {
Object value = getAttributeValue("value", "");
if (value instanceof AttributeObject) {
LOGGER.error("yes1");
}
if (value instanceof IAttributeObject) {
LOGGER.error("yes2");
}
LOGGER.error("getSubmittedValue -> " + value.toString());
}
String submitVal = (String) getMeasure().getValue() + " " + (String) getUnit().getValue();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("getSubmittedValue()" + submitVal);
}
return submitVal;
}
// Helpers
// ------------------------------------------------------------------------------------
/**
* Return specified attribute value or otherwise the specified default if
* it's null.
*
* @param <T>
* the generic type
* @param key
* the key
* @param defaultValue
* the default value
* @return the attribute value
*/
@SuppressWarnings("unchecked")
private <T> T getAttributeValue(String key, T defaultValue) {
T value = (T) getAttributes().get(key);
return (value != null) ? value : defaultValue;
}
// Getters/setters
// ----------------------------------------------------------------------------
/**
* Gets the measure.
*
* @return the measure
*/
public UIInput getMeasure() {
return measure;
}
/**
* Gets the unit.
*
* @return the unit
*/
public UISelectOne getUnit() {
return unit;
}
/**
* Sets the unit.
*
* @param unit
* the new unit
*/
public void setUnit(UISelectOne unit) {
this.unit = unit;
}
/**
* Sets the measure.
*
* @param measure
* the new measure
*/
public void setMeasure(UIInput measure) {
this.measure = measure;
}
}
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:p="http://primefaces.org/ui"
xmlns:pe="http://primefaces.org/ui/extensions">
<cc:interface componentType="testComponent">
<cc:attribute type="java.lang.Object" name="value" required="true" />
<cc:attribute type="java.util.List" name="list"/>
</cc:interface>
<cc:implementation>
<h:panelGrid columns="3">
<p:inputText id="measure" binding="#{cc.measure}">
<f:ajax render="unit" />
</p:inputText>
<p:selectOneMenu id="unit" binding="#{cc.unit}">
<f:selectItem noSelectionOption="true" itemLabel=" " itemValue="" />
<f:selectItems value="#{cc.attrs.list}" var="option" itemLabel="#{option.getShortName()}" itemValue="#{option.getShortName()}" />
<f:ajax render="measure" />
</p:selectOneMenu>
</h:panelGrid>
</cc:implementation>
</ui:composition>
public class TestSelect {
private static final Logger LOGGER = Logger.getLogger(TestController.class);
String ShortName;
public TestSelect(String shortName) {
super();
ShortName = shortName;
}
public String getShortName() {
return ShortName;
}
public void setShortName(String shortName) {
ShortName = shortName;
}
@Override
public boolean equals(Object obj) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("this " + this.ShortName);
LOGGER.debug("compared " + obj.toString());
}
if (this.ShortName.equals((String)obj)) {
return true;
}
return false;
}
@Override
public String toString() {
return "TestSelect [ShortName=" + ShortName + "]";
}
}