在我的应用程序中,我有一个键(字符串)列表,用户可以在其中选择其中一个。在用户界面中,将根据当前区域设置输出密钥:
<h:selectOneMenu value="#{bean.selectedKey}">
<f:selectItems value="#{bean.allKeys}" var="_key" itemLabel="#{msgs[_key]}" />
</h:selectOneMenu>
我的设置使用由faces-config.xml
配置的标准资源包,如BalusC所解释的in this answer。上例中的msgs
是资源包变量的名称。
我现在想要的是selectOneMenu
中的项目按字母顺序排序。当然,顺序取决于使用的区域设置。问题是,我不能/不会在backing-bean中进行排序,因为我不知道JSF页面将如何输出密钥。
这个问题对我来说似乎很通用,所以我想知道解决这类问题的最佳做法是什么。
(当然问题不仅适用于selectOneMenu
。任何将在用户界面中输出的列表/集合都会遇到同样的问题。)
答案 0 :(得分:6)
你基本上有两种选择。
在JS的一点帮助下在客户端排序。为简单起见,我假设您正在使用jQuery。
<h:selectOneMenu ... styleClass="ordered">
$("select.ordered").each(function(index, select) {
var $select = $(select);
$select.find("option").sort(function(left, right) {
return left.text == right.text ? 0 : left.text < right.text ? -1 : 1;
}).appendTo($select);
if (!$select.find("option[selected]").length) {
select.options.selectedIndex = 0;
}
});
在服务器端排序,您可以在其中创建List<SelectItem>
并通过注入抓取#{msgs}
。假设您正在使用CDI,因此无法使用@ManagedProperty("#{msgs}")
,那么您需要首先为其创建一个生产者。为简单起见,我假设您正在使用OmniFaces(也会根据您的问题历史记录确认)。
public class BundleProducer {
@Produces
public PropertyResourceBundle getBundle() {
return Faces.evaluateExpressionGet("#{msgs}");
}
}
然后,您可以在与<f:selectItems value>
关联的支持bean中使用它,如下所示:
private static final Comparator<SelectItem> SORT_SELECTITEM_BY_LABEL = new Comparator<SelectItem>() {
@Override
public int compare(SelectItem left, SelectItem right) {
return left.getLabel().compareTo(right.getLabel());
}
};
private List<SelectItem> allKeys;
@Inject
private PropertyResourceBundle msgs;
@PostConstruct
public void init() {
allKeys = new ArrayList<>();
for (String key : keys) {
allKeys.add(new SelectItem(key, msgs.getString(key)));
}
Collections.sort(allKeys, SORT_SELECTITEM_BY_LABEL);
}
并在没有var
的情况下直接引用它,如下所示:
<f:selectItems value="#{bean.allKeys}" />