我有以下选择一个菜单。我有一个转换器用于我的" Intezet" (机构)对象。
<p:selectOneMenu id="bekuldo" filter="true" filterMatchMode="contains" required="true" converter="intezetConverter" disabled="#{iratFelvitelView.disabled}" value="#{iratFelvitelView.bekuldo}" placeholder="Válaszd ki vagy add meg!" editable="true">
<f:selectItem noSelectionOption="true" itemLabel="Válassz egyet:" itemValue="#{null}" itemDisabled="#{iratFelvitelView.bekuldo ne null}" />
<f:selectItems value="#{dataFromDBean.intezetek}" var="intezet" itemLabel="#{intezet.name}" itemValue="#{intezet}" />
</p:selectOneMenu>
@FacesConverter(value = "intezetConverter")
public class IntezetConverter 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());
Intezet object = null;
try {
UUID guid = UUID.fromString(id);
object = objects.getIntezet(guid);
} catch (IllegalArgumentException e) {
e.printStackTrace();
object = new Intezet(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 ((Intezet) obj).getId().toString();
}
}
getAsObject
中调用的构造函数是:
public Intezet(String name) {
super();
this.id = UUID.randomUUID();
this.name = name;
this.passziv = false;
}
基本上我的逻辑是selectOneMenu
使用现有对象作为值,用户可以选择,并且还添加新值,即String,如果传递了String,则不会有id发现,所以字符串作为id传递,然后如果一个id不能被解析为UUID,那么它不是一个UUID字符串,所以创建一个新对象,由服务器保存提交表格。
然而,问题是,当editable="true"
存在时,selectOneMenu
总是将String
传递给转换器,但不只是String
,而是itemLabel
{1}}值,即机构的名称表示。即使是noselectoption也是以它的itemLabel而不是#{null}
传递的。
因此,无论用户输入新值还是选择现有值,始终将itemLabel
属性传递给转换器,因此我的转换器将其视为新值并尝试创建新的Institution。这是JSF
或PrimeFaces
中的已知错误吗?
根据Usagi Miyamoto的建议,<p:autoComplete>
是我的问题的解决方法。
以下代码按照我最初的需要(就功能而言)起作用:
<p:autoComplete id="bekuldo" value="#{iratFelvitelView.bekuldo}" completeMethod="#{iratFelvitelView.completeIntezet}"
var="intezet" itemLabel="#{intezet.name}" itemValue="#{intezet}" converter="intezetConverter" dropdown="true" disabled="#{iratFelvitelView.disabled}"/>
使用以下完整方法:
public Collection<Intezet> completeIntezet(String query) {
Collection<Intezet> filteredIntezet = new ArrayList<>();
for (Intezet intezet : intezetek) {
if (intezet.getName().toLowerCase().contains(query.toLowerCase().trim())) {
filteredIntezet.add(intezet);
}
}
return filteredIntezet;
}
答案 0 :(得分:0)
它是RichFaces 3.x
,所以JSF 1.x
,但类似的内容也适用于JSF 2.x
和PrimeFaces
。
XHTML:
<a4j:region>
<h:inputText id="person" value="#{bean.item.id}">
<a4j:support event="onblur" action="#{bean.listener}" reRender="partner" />
</h:inputText>
<rich:suggestionbox id="partnerSuggest" for="partner" var="part" fetchValue="#{part.id}"
suggestionAction="#{bean.suggest}" reRender="partner">
<rich:column><h:outputText value="#{part.id}"/></rich:column>
<rich:column><h:outputText value="#{part.name}"/></rich:column>
<a4j:support event="onselect" action="#{bean.listener}" reRender="partner" />
</rich:suggestionBox>
</a4j:region>
Bean.java:
public class Bean
{
// Currently selected/edited Person
private Person item = new Person();
// Getters and Setters omitted...
// This method is invoked to present a list fro the <rich:suggestionbox> component.
// It receives the typed in text as parameter.
public List<Partner> suggest( Object value )
{
// Returns a list of partner filtered by the given value.
// In my case it could be a name or an ID...
}
// This method (an action) is called when the input field is lost focus (onblur event) or
// a selection is made from the suggestion list.
// It checks wheter the input field contains a valid ID, and sets the bean to the correct
// partner it loaded.
public String listener()
{
String value = this.item.getId();
final Partner who = Partner.find( value ); // To retrieve the partner
if ( null != who )
{
this.item = who;
}
return null;
}
}