【发布时间】:2017-08-11 07:22:26
【问题描述】:
我有以下选择一个菜单。我的“Foo”对象有一个转换器。
<p:selectOneMenu id="sender" filter="true" filterMatchMode="contains" required="true" converter="fooConverter" disabled="#{myView.disabled}" value="#{myView.sender}" placeholder="Pick one or create new!" editable="true">
<f:selectItem noSelectionOption="true" itemLabel="Pick one:" itemValue="#{null}" itemDisabled="#{myView.sender ne null}" />
<f:selectItems value="#{dataFromDBean.foos}" var="foo" itemLabel="#{foo.name}" itemValue="#{foo}" />
</p:selectOneMenu>
@FacesConverter(value = "fooConverter")
public class FooConverter implements Converter {
@Override
public Object getAsObject(FacesContext ctx, UIComponent uiComponent, String id) {
ValueExpression vex = ctx.getApplication().getExpressionFactory().createValueExpression(ctx.getELContext(),
"#{dataFromDBean}", DataFromDBean.class);
DataFromDBean objects = (DataFromDBean) vex.getValue(ctx.getELContext());
Foo object = null;
try {
UUID guid = UUID.fromString(id);
object = objects.getFoo(guid);
} catch (IllegalArgumentException e) {
e.printStackTrace();
object = new Foo(id);
}
return object;
}
@Override
public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object obj) {
if (obj == null)
return "";
if (obj.getClass().equals(String.class)) {
return (String) obj;
}
return ((Foo) obj).getId().toString();
}
}
而getAsObject中调用的构造函数是:
public Foo(String name) {
super();
this.id = UUID.randomUUID();
this.name = name;
this.passive = false;
}
基本上我的逻辑是selectOneMenu 使用现有对象作为值,用户可以选择,还可以添加新值,这是一个字符串,如果传递一个字符串,则找不到 id,所以字符串作为 id 传递,然后如果 id 不能解析为 UUID,则它不是 UUID 字符串,因此创建了一个新对象,该对象将在提交表单时由服务器保存。
但是,问题是,当存在editable="true" 时,selectOneMenu 总是将String 传递给转换器,但不仅仅是任何String,而是itemLabel 值,即名称该机构的代表。甚至 noselectoption 也作为 itemLabel 传递,而不是 #{null}。
因此,无论用户输入新值还是选择现有值,itemLabel 属性总是传递给转换器,因此我的转换器将其视为新值并尝试创建新机构。这是JSF 或PrimeFaces 中的已知错误吗?
正如 Usagi Miyamoto 所建议的,<p:autoComplete> 是解决我的问题的方法。
以下代码可以按照我最初想要的方式工作(就功能而言):
<p:autoComplete id="sender" value="#{myView.sender}" completeMethod="#{myView.completeFoo}"
var="foo" itemLabel="#{foo.name}" itemValue="#{foo}" converter="fooConverter" dropdown="true" disabled="#{myView.disabled}"/>
用下面的完整方法:
public Collection<Foo> completeFoo(String query) {
Collection<Foo> filteredFoo = new ArrayList<>();
for (Foo foo : foos) {
if (foo.getName().toLowerCase().contains(query.toLowerCase().trim())) {
filteredFoo.add(foo);
}
}
return filteredFoo;
}
【问题讨论】:
-
不要使用
HTML/JavaScript/CSSsn-ps 来显示Java/XHTML源,因为它们不会运行... -
应该改用
<p:autoComplete>... -
@UsagiMiyamoto 它也不会在没有 bean 和服务器的情况下运行,但是我应该使用什么来代替呢?我是stackoverflow的新手
-
@UsagiMiyamoto
据我所知是不可编辑的,这对我来说是必需的。需要用户能够输入一个全新的值,然后将其保存到数据库中。 -
“不可编辑”是什么意思? primefaces.org/showcase/ui/input/autoComplete.xhtml
标签: java jsf primefaces jsf-2.2 selectonemenu