问题描述
例如:
<p:selectOneMenu value="#{UserBean.country}" id="countryId">
<f:selectItem itemLabel="Japan" itemValue="Japan"/>
<f:selectItem itemLabel="Russia" itemValue="Russia"/>
<f:selectItem itemLabel="India" itemValue="India"/>
<p:ajax listener="#{UserBean.onChangeCountry}" process="@this"/>
</p:selectOneMenu>
像上面一样,我在其他 jsf 页面中有许多其他的 selectOneMenu 不是排序形式,我想要一个解决方案,其中使用自定义标记围绕 selectOneMenu 标记将按排序顺序显示内容(或者也可以建议任何其他方式我们可以做到这一点)
解决方法
您不需要自定义标签。
在 p:selectOneMenu
的情况下,您可以只使用 f:selectItems
(复数)并返回一个排序的集合(替换您的个人 f:selectItem
标签)。在这种情况下,这将类似于;
<f:selectItems value="#{view.countries}"/>
其中 countries
是一个 getter,getCountries()
,返回根据您的选择排序的 Map<String,String>
列表。
想象一下,虽然没有 f:selectItems
,但我们唯一可用的选项是 f:selectItem
(单数)——就像你的例子一样。那么解决方案是使用 JSF 预渲染钩子并在渲染该部分之前对 JSF 组件进行排序。你可以在这里阅读它是如何工作的; Variable order of components (panels) in JSF page。在该示例中,p:panel
组件列表在 h:panelGroup
中随机排列。不过,它可以很容易地应用于这种情况。
为了使它更透明并将f:event
标签隐藏到页面上的预渲染挂钩,您可以更进一步定义一个复合组件;
https://stackoverflow.com/tags/composite-component/info
这个复合组件可以只使用一个 selectOneMenu
并引入一个 sort
属性,该属性允许您调用上述的排序预渲染钩子,具体取决于 {{1} } 属性为真或假。
您可以为 p:selectOneMenu
组件创建自定义渲染器。创建一个新类,例如 my.custom.MySelectOneMenuRenderer
,并扩展 SelectOneMenuRenderer
。在此,您希望将 @Override
方法encodeInput
改为:
public class MySelectOneMenuRenderer extends SelectOneMenuRenderer {
@Override
protected void encodeInput(FacesContext context,SelectOneMenu menu,String clientId,List<SelectItem> selectItems,Object values,Object submittedValues,Converter converter) throws IOException {
// Sort the items
Collections.sort(selectItems,Comparator.comparing(SelectItem::getLabel));
// Delegate to super to continue rendering
super.encodeInput(context,menu,clientId,selectItems,values,submittedValues,converter);
}
}
我已经使用 PrimeFaces 10 进行了检查。如果您需要不同 PrimeFaces 版本的源代码,请选中 SelectOneMenuRenderer
source code 并选择相应的版本标签。请注意,您需要覆盖的方法在其他版本中可能会有所不同(不太可能,但可能)。
将您的自定义渲染器添加到您的 render-kit
中的 faces-config.xml
部分,例如:
<render-kit>
<renderer>
<component-family>org.primefaces.component</component-family>
<renderer-type>org.primefaces.component.SelectOneMenuRenderer</renderer-type>
<renderer-class>my.custom.MySelectOneMenuRenderer</renderer-class>
</renderer>
</render-kit>
请注意,对于任何 p:selectOneMenu
渲染,每次都会对选项进行排序,这会带来性能损失。