如何在我的应用程序的每个 p:selectOneMenu 中对 f:selectItems 进行排序?

How to sort f:selectItems in each p:selectOneMenu of my application?

例如:

<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(复数)和 return 排序集合(替换您的个人 f:selectItem 标签)。在这种情况下,这将类似于;

<f:selectItems value="#{view.countries}"/>

其中 countries 是 getter、getCountries()、returning 的列表 Map<String, String> 根据您的选择排序。

想象一下虽然没有 f:selectItems,但我们唯一可用的选项是 f:selectItem(单数)- 就像您的示例一样。那么解决方案就是使用 JSF 预呈现挂钩并在呈现该部分之前对 JSF 组件进行排序。您可以在此处准确阅读其工作原理; 。在该示例中,p:panel 个组件的列表在 h:panelGroup 中随机洗牌。不过,它可以很容易地应用于这种情况。

为了更加透明,将f:event标签隐藏到页面的pre-render hook中,可以更进一步,定义一个复合组件;

https://whosebug.com/tags/composite-component/info

这个复合组件可以只使用 selectOneMenu 并引入一个 sort 属性,该属性允许您调用排序预渲染挂钩,具体取决于 sort 属性是真还是假。

您可以为 p:selectOneMenu 组件创建自定义渲染器。创建一个新的 class,比如 my.custom.MySelectOneMenuRenderer,并扩展 SelectOneMenuRenderer。在此你想要 @OverrideencodeInput 方法类似于:

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 and select the according version tag (note that from PrimeFaces 11 the path changed)。请注意,您需要覆盖的方法在其他版本中可能有所不同(不太可能,但可能)。

将自定义渲染器添加到 faces-config.xml 中的 render-kit 部分,例如:

<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 渲染的选项进行排序,这会带来性能损失。