sortingjsfselectonemenu

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


Eg:

<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>

Like above I have many other selectOneMenu in other jsf pages which is not in sorted form, I want a solution where in surrounding the selectOneMenu tag with the custom tag will display the contents in sorting order (or can suggest any other way also we can achieve this)


Solution

  • You could create a custom renderer for the p:selectOneMenu component. Create a new class, say my.custom.MySelectOneMenuRenderer, and extend SelectOneMenuRenderer. In this you want to @Override the encodeInput method to something like:

    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);
      }
    
    }
    

    I've checked this with PrimeFaces 10. If you need the source for a different PrimeFaces version, check the SelectOneMenuRenderer source code and select the according version tag (note that from PrimeFaces 11 the path changed). Note that the method you need to override, might be different in other versions (not likely, but possible).

    Add your custom renderer to the render-kit section in your faces-config.xml like:

    <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>
    

    Please note that this will sort the options every time for any p:selectOneMenu render, which comes with a performance penalty.