Reputation: 33
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)
Upvotes: 3
Views: 1613
Reputation: 20198
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.
Upvotes: 3
Reputation: 2321
You don't need a custom tag.
In the case of a p:selectOneMenu
you can just use f:selectItems
(plural) and return a sorted collection (replacing your individual f:selectItem
tags). In this case, that would be something like;
<f:selectItems value="#{view.countries}"/>
Where countries
is a getter, getCountries()
, returning a list of Map<String, String>
sorted according to your choice.
Imagine for a second there was no f:selectItems
though, and the only option available to us was f:selectItem
(singular) - like in your example. Then the solution would be to use a JSF pre-render hook and sort the JSF components before that section was rendered. You can read exactly how this works here; Variable order of components (panels) in JSF page. In that example, a list of p:panel
components are shuffled randomly inside a h:panelGroup
. It can easily be applied to this case though.
To make it more transparent and hide the f:event
tag to the pre-render hook on the pages, you could go one step further and define a composite component;
https://stackoverflow.com/tags/composite-component/info
This composite component could just use a selectOneMenu
and introduce a sort
attribute that would allow you to invoke the sorting pre-render hook as described above depending on if the value of the sort
attribute is true or false.
Upvotes: 3