p:selectOneMenu不会通过List <string>

时间:2015-09-23 09:27:30

标签: jsf jsf-2 primefaces selectonemenu

我试图让Primefaces 5.2 selectOneMenu显示图像及其文件名。这就是我的xhtml目前的样子:

<h:form>
<h:panelGrid id="createPanelGrid" columns="2">
    <p:outputLabel value="Service Logo:" />
    <p:selectOneMenu value="#{imageBean.selectedImage}" var="l">
        <f:selectItem itemLabel="Select a logo" itemValue="" />
        <f:selectItems value="#{imageBean.imageList}" var="logo" itemLabel="#{logo}" itemValue="#{logo}" />
        <p:column>
            <p:graphicImage value="#{imageBean.imageFolder}/#{l}" style="max-width:50px;max-height:50px;" />
        </p:column>
        <p:column>#{l}</p:column>
    </p:selectOneMenu>
</h:panelGrid>

ManagedBean(imageBean)有

public List<String> getImageList () {
    List<String> imageList = new ArrayList<String>();
    File[] files = absoluteImageFolder.listFiles();
    for (File file : files) {
        imageList.add(file.getName());
    }        
    return imageList;
}

private String selectedImage;

public String getSelectedImage() {
    return selectedImage;
}

public void setSelectedImage(String selectedImage) {
    this.selectedImage = selectedImage;
}

但是,图片不会在网页上呈现,只会在文件名上呈现(我发布截图但我没有足够的声誉)。我没有得到两列(首先是图像,然后是文件名),我只是获取文件名。

当我将文件名字符串包装到POJO并使用转换器时,它可以工作 - 但只是使用字符串它不会。

如何才能使用Strings?

2 个答案:

答案 0 :(得分:9)

这种尴尬的行为由SelectOneMenuRenderer source code确认(行号匹配5.2):

260            if(itemValue instanceof String) {
261                writer.startElement("td", null);
262                writer.writeAttribute("colspan", columns.size(), null);
263                writer.writeText(selectItem.getLabel(), null);
264                writer.endElement("td");
265            } 
266            else {
267                for(Column column : columns) {
268                    writer.startElement("td", null);
269                    renderChildren(context, column);
270                    writer.endElement("td");
271                }
272            }

因此,如果商品值是String的实例,则完全忽略通过<p:column>的自定义内容。这确实没有任何意义。直观的期望是,var属性和/或<p:column>子项的存在会切换自定义内容。您最好向PrimeFaces人员报告问题,以解释/改进这一点。

除了提供非String类型的项值之外,解决方法是使用自定义渲染器覆盖SelectOneMenuRenderer,该渲染器将String包装在另一个碰巧返回的对象中其toString()中的值完全相同,例如StringBuilder。这样,渲染器将被欺骗,因为值不是String的实例。很高兴他们没有检查instanceof CharSequence

public class YourSelectOneMenuRenderer extends SelectOneMenuRenderer {

    @Override
    protected void encodeOptionsAsTable(FacesContext context, SelectOneMenu menu, List<SelectItem> selectItems) throws IOException {
        List<SelectItem> wrappedSelectItems = new ArrayList<>();

        for (SelectItem selectItem : selectItems) {
            Object value = selectItem.getValue();

            if (value instanceof String) {
                value = new StringBuilder((String) value);
            }

            wrappedSelectItems.add(new SelectItem(value, selectItem.getLabel()));
        }

        super.encodeOptionsAsTable(context, menu, wrappedSelectItems);
    }

}

要使其运行,请在faces-config.xml

中按以下方式注册
<render-kit>
    <renderer>
        <component-family>org.primefaces.component</component-family>
        <renderer-type>org.primefaces.component.SelectOneMenuRenderer</renderer-type>
        <renderer-class>com.example.YourSelectOneMenuRenderer</renderer-class>
    </renderer>
</render-kit>

答案 1 :(得分:0)

原因是Primefaces库正在考虑var组件的selectOneMenu属性中的bean,但是您给的String对象不是bean。因此库根本不呈现任何列叠加。您需要var属性中的bean(包装器)和converter属性中的相应Converter。