为什么我不能在复合组件的 encodeBegin 中设置 f:selectItems?



我试图了解如何对复合组件进行编程,并遵循了 balusc 和其他人的伟大示例,但我错过了一些东西。

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:cc="http://java.sun.com/jsf/composite">
<cc:interface componentType="simpleComponent">
    <cc:attribute name="value" required="true" type="example.LanguageDefinition"/>
    <cc:attribute name="possibilities" default="de_DE" type="java.lang.String"/>
</cc:interface>
<cc:implementation>     
    <p:selectOneMenu binding="#{cc.inputComponent}" converter="omnifaces.SelectItemsConverter" var="l"
        value="#{cc.attrs.value}">
        <p:ajax update="@form"/>
        <f:selectItems value="#{cc.languages}" var="l" itemLabel="#{l.label}"
            itemValue="#{l}" />
        <p:column>#{l.label}</p:column>
        <p:column>
            <p:graphicImage name="#{l.imgPath}" />
        </p:column>
    </p:selectOneMenu>      
</cc:implementation>

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.faces.component.FacesComponent;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIInput;
import javax.faces.component.UINamingContainer;
import javax.faces.context.FacesContext;
import example.LanguageDefinition;
@FacesComponent("simpleComponent")
public class SimpleComponent extends UIInput implements NamingContainer {
private UIInput  inputComponent;
public UIInput getInputComponent() {
    return inputComponent;
}
public void setInputComponent(UIInput inputComponent) {
    this.inputComponent = inputComponent;
}
@Override
public Object getSubmittedValue() {
    return inputComponent.getSubmittedValue();
}
@Override
protected Object getConvertedValue(FacesContext context, Object newSubmittedValue) {
   return (String) newSubmittedValue;
}
@Override
public String getFamily() {
    return UINamingContainer.COMPONENT_FAMILY;
}
@Override
public void encodeBegin(FacesContext context) throws IOException {
    String possibilities = getAttributeValue("possibilities", "en_US");
    // In theory, build based on incoming possibilities, now hard code
    List<LanguageDefinition> languages = new ArrayList<LanguageDefinition>();
    languages.add(new LanguageDefinition("pt_PT",
            "images/flags/PT.gif", "Português (Portugal)"));
    languages.add(new LanguageDefinition("cs_CZ",
            "images/flags/CZ.gif", "Czech (Czech Republic)"));
    getStateHelper().put("languages", languages);
    super.encodeBegin(context);
}
@SuppressWarnings("unchecked")
public List<LanguageDefinition> getLanguages() {
    return (List<LanguageDefinition>) getStateHelper().get("languages");
}
/**
 * Return specified attribute value or otherwise the specified default if it's null.
 */
@SuppressWarnings("unchecked")
private <T> T getAttributeValue(String key, T defaultValue) {
    T value = (T) getAttributes().get(key);
    return (value != null) ? value : defaultValue;
}
}

像这样调用是行不通的:

<ex:simpleComponent value="#{compBean.selected}"/>

一切都很好,但提交的值永远不会传回我的"compBean"。 但是,如果我以任何其他方式设置选择项目"语言",而不是在 encodeBegin 中执行此操作,它可以工作......作为具有 getter 和 setter 的成员变量,或使用以下代码:

<c:set target="#{cc}" property="possibilities" value="#{cc.attrs.possibilities}"/>

结合这个更简单的类:

import java.util.ArrayList;
import java.util.List;
import javax.faces.component.FacesComponent;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIInput;
import javax.faces.component.UINamingContainer;
import example.LanguageDefinition;
@FacesComponent("simpleComponent")
public class SimpleComponent extends UIInput implements NamingContainer {
@Override
public String getFamily() {
    return UINamingContainer.COMPONENT_FAMILY;
}
public void setPossibilities(String possibilities) {
    if (getStateHelper().get("possibilities") == null) {
        List<LanguageDefinition> languages = new ArrayList<LanguageDefinition>();
        languages.add(new LanguageDefinition("pt_PT",
                "images/flags/PT.gif", "Português (Portugal)"));
        languages.add(new LanguageDefinition("cs_CZ",
                "images/flags/CZ.gif", "Czech (Czech Republic)"));
        getStateHelper().put("languages", languages);
getStateHelper().put("possibilities", possibilities);
    }
}
public String getPossibilities() {
    return (String) getStateHelper().get("possibilities");
}
@SuppressWarnings("unchecked")
public List<LanguageDefinition> getLanguages() {
    return (List<LanguageDefinition>) getStateHelper().get("languages");
}
}

但是,这样做似乎不对(不是 balusc 的做法),所以我只是想理解。 哪种方式更好? 假设第一个,为什么我的不起作用?

谢谢!

所以... 这不起作用的原因是因为我忘记在我的自定义下拉列表值对象"示例上实现可序列化。语言定义"。

希望下一个人不必像我那样大海捞针:)

最新更新