1

编辑:问题是当复合组件包装在 ui:repeat 或 h:datatable 以及 ap:dialog 中时

使用http://balusc.blogspot.de/2013/01/composite-component-with-multiple-input.html我在 ap:dialog 中提交包含复合组件的表单似乎有问题。

调用普通 p:boolean 和此类字段的设置器,但不会调用来自复合组件的设置器,尽管 getSubmittedvalue 是。

初始值为空,当不在模态 p:dialog 中时,同样的工作。

我可以在调试/配置文件模式下清楚地看到它。

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 中时,相同的东西有效(如果这很重要,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;
}

}

豆:

public class BeanObject {
double val;
String type;

public BeanObject(double val, String type) {
    super();
    this.val = val;
    this.type = type;
}
public double getVal() {
    return val;
}
public void setVal(double val) {
    this.val = val;
}
public String getType() {
    return type;
}
public void setType(String type) {
    this.type = type;
}

}

小面:

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

面组件:

@FacesComponent("testComponent") 公共类 TestComponent 扩展 UIInput 实现 NamingContainer {

    /** 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>

助手选择bean:

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 + "]";
    }

}
4

1 回答 1

0

解决方案是几件事的组合:

  • 使用 c:forEach 而不是 ui repeat(我知道它在 jsf 2 中应该是不好的做法)
  • 使用 @SessionScoped 注释作为表单支持 bean(控制器)

听起来很奇怪,这两件事让问题消失了。(目前 :)

于 2013-04-11T13:13:11.750 回答