简体   繁体   English

当属性 editable 为 true 时,SelectOneMenu 传递 itemLabel 而不是 itemValue

[英]SelectOneMenu passes itemLabel instead of itemValue when attribute editable is true

I have the following select one menu.我有以下选择一个菜单。 And I have a converter for my "Foo" object.我有一个用于“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();
        }

    }

And the constructor called in getAsObject is:getAsObject调用的构造函数是:

    public Foo(String name) {
            super();
            this.id = UUID.randomUUID();
            this.name = name;
            this.passive = false;
        }

Basically my logic is that the selectOneMenu uses the existing objects as values, which the user can select, and also add new value, which is a String, and if a String is passed, than no id will be found, so the string is passed as id instead, and then if an id can't be parsed into a UUID, then it is not a UUID string, so a new object is created, which will be saved by the server on submitting the form.基本上我的逻辑是selectOneMenu使用现有对象作为值,用户可以选择这些值,并添加新值,它是一个字符串,如果传递一个字符串,则不会找到 id,因此传递字符串改为 id,然后如果 id 无法解析为 UUID,则它不是 UUID 字符串,因此会创建一个新对象,该对象将在提交表单时由服务器保存。

However, the problem is, that when editable="true" is present, the selectOneMenu always passes a String to the converter, but not just any String , but the itemLabel value, which is the name representation of the Institution.然而,问题是,当editable="true"存在时, selectOneMenu总是将String传递给转换器,但不仅仅是任何String ,而是itemLabel值,它是机构的名称表示。 Even the noselectoption is passed as it's itemLabel and never #{null} .甚至 noselectoption 也作为 itemLabel 传递,而不是#{null} So regardless if the user enters a new value, or selects an existing one, always the itemLabel attribute is passed to the converter, so my converter sees it as a new value and tries to create the new Institution.因此,无论用户输入新值还是选择现有值, itemLabel属性始终传递给转换器,因此我的转换器将其视为新值并尝试创建新机构。 Is this a known bug in JSF or PrimeFaces ?这是JSFPrimeFaces的已知错误吗?


As suggested by Usagi Miyamoto, <p:autoComplete> is a workaround to my issue.正如 Usagi Miyamoto 所建议的, <p:autoComplete>是我的问题的一种解决方法。

The following code works as I originally wanted it (in terms of functionality):以下代码按我原先想要的方式工作(在功能方面):

    <p:autoComplete id="sender" value="#{myView.sender}" completeMethod="#{myView.completeFoo}"
                        var="foo" itemLabel="#{foo.name}" itemValue="#{foo}" converter="fooConverter" dropdown="true" disabled="#{myView.disabled}"/>

With the following complete method:使用以下完整方法:

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

It is RichFaces 3.x , so JSF 1.x , but something similar should work in JSF 2.x with PrimeFaces , too.它是RichFaces 3.x ,所以是JSF 1.x ,但类似的东西也应该在带有PrimeFaces JSF 2.x工作。

XHTML: 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:豆.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;
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM