p:selectOneMenu 不通过列表 <String> 上的 p:column 呈现自定义内容
p:selectOneMenu doesn't render custom content via p:column on List<String>
我正在尝试让 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;
}
但是,网页上没有呈现图像,只有文件名(我 post 截图但我没有足够的声誉)。我没有得到两列(首先是图像,然后是文件名),我只得到文件名本身。
当我将文件名字符串包装到 POJO 中并使用转换器时它可以工作 - 但仅使用字符串时它不起作用。
我怎样才能让它只使用字符串?
原因是 Primefaces 库在 selectOneMenu
组件的 var
属性中检测到一个 bean,但您提供的不是 beans 的 String 对象。所以库根本不呈现任何列覆盖。您将需要 var
属性中的 bean(包装器)和 converter
属性中的相应转换器。
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
属性 and/or <p:column>
子项的存在而切换。您最好向 PrimeFaces 人员报告问题 explain/improve 这个。
除了提供非 String
类型的项值之外,解决方法是使用自定义渲染器覆盖 SelectOneMenuRenderer
,该渲染器将 String
包装在另一个发生的对象中使其return中的值完全相同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>
我正在尝试让 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;
}
但是,网页上没有呈现图像,只有文件名(我 post 截图但我没有足够的声誉)。我没有得到两列(首先是图像,然后是文件名),我只得到文件名本身。
当我将文件名字符串包装到 POJO 中并使用转换器时它可以工作 - 但仅使用字符串时它不起作用。
我怎样才能让它只使用字符串?
原因是 Primefaces 库在 selectOneMenu
组件的 var
属性中检测到一个 bean,但您提供的不是 beans 的 String 对象。所以库根本不呈现任何列覆盖。您将需要 var
属性中的 bean(包装器)和 converter
属性中的相应转换器。
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
属性 and/or <p:column>
子项的存在而切换。您最好向 PrimeFaces 人员报告问题 explain/improve 这个。
除了提供非 String
类型的项值之外,解决方法是使用自定义渲染器覆盖 SelectOneMenuRenderer
,该渲染器将 String
包装在另一个发生的对象中使其return中的值完全相同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>