Primefaces autocomplete with POJO and String value

2019-04-13 20:23发布

I need to have an autocomplete with string value, because users can't be restricted to provided items by autocomplete method, but they should be able to write anything in the search field. If they want, they can choose from suggestions as well.

Now I am always getting /archive/overview.xhtml @28,57 itemLabel="#{item.name}": The class 'java.lang.String' does not have the property 'name'.

XHTML:

<p:autoComplete id="vyraz" value="#{archiveView.searchString}"
  completeMethod="#{archiveView.autocomplete}"
  var="item" itemLabel="#{item.name}" itemValue="#{item.name}"
  converter="archiveConverter" forceSelection="false" minQueryLength="2"
  autoHighlight="false" effect="fade">

  <p:column>
    <h:outputText value="#{item.name}"/>
    <h:outputText value=" (Barcode: #{item.barcode})" rendered="#{item.barcode ne null}"/>
  </p:column>

  <p:column>
   <h:outputText value="#{item.type.label}" style="font-weight: bold;"/>
  </p:column>
</p:autoComplete>

Bean:

private String searchString; // + getter and setter

public List<ArchiveAutoCompleteDto> autocomplete(String query) {
    // get and return from lucene index/database
}

Is there a way to implement this (Primefaces 5.2)?
Thanks!

1条回答
太酷不给撩
2楼-- · 2019-04-13 20:43

itemValue property in p:autocomplete can be used as a lightweight replacement of converters in just simple scenarios when you do not perform any update/refresh of the p:autocomple widget (which basically means you cannot perform update="@form" or similar)

So basically there are 3 cases:

Pojo + Converter

Setting the attributue var to some expression is mandatory to enable the "pojo mode" in PrimeFaces.

<p:autoComplete 
     value="#{backingBean.myPojo}"
     completeMethod="#{backingBean.autocomplete}
     var="pojo" itemLabel="#{pojo.label}"
     itemValue="#{pojo}" converter="pojoConverter">
</p:autoComplete>

In this scenario var="pojo" is an instance of class A. value="#backingBean.myPojo}" is a variable of type A. itemValue="#{pojo}" is evaluated when you ask for the suggestion list, the result is passed to the converter via getAsString which produces the value to encode in html (eg.:v1).
When you select an element from the list (eg.:v1) it is passed back to the converter into getAsObject which gives you in return an object of type A to set in the backing bean. The converter as usual has full responsibility in translating from Pojo to HTML value and vice versa.

public interface Converter {

    // @return *K* the value to be used in html
    // @param obj is provided by the expression (itemValue="#{pojo}")
    public String getAsString(FacesContext context, UIComponent component, Object obj);

     // build the pojo identified by String *K*
     // @param value *K*
     public Object getAsObject(FacesContext context, UIComponent component, String value);         
}

Pojo + String

In this case you have a pojo with a String field to extract and to use in the backing bean.

<p:autoComplete value="#{backingBean.myStringValue}" 
    completeMethod="#{backingBean.autocomplete} 
    var="pojo" itemLabel="#{pojo.label}" 
    itemValue="#{pojo.stringKey}">
</p:autoComplete>

The flow is the same but

  1. itemValue must evaluate to a String to avoid ClassCasts.
  2. itemValue is used as html value directly (as if it was produced from the Converter#getAsString) and set to "#{backingBean.myStringValue}" once selected.
  3. "#{backingBean.myStringValue}" must be a string of course.

Everything works fine until you try to perform refresh the p:autoComplete widget (for example update="@form"). Primefaces re-evaluates the itemLabel(because, for some reason, it does not store the itemLabel in the ViewState) using the value from the backing bean which is a String. Therefore you get the error. Actually there is no solution to this problem but to provide an implementation as in case 1).

Plain String Values

Not covered here.

查看更多
登录 后发表回答