PrimeFaces p:autoComplete not converting in ArrayList - jsf

I'm converting from RichFaces to PrimeFaces 11.0 and replacing a custom component based on the old rich:suggestionBox with p:autoComplete. This works perfectly in most code where the value refers to a POJO property. However I'm finding difficulty getting p:autoComplete to set the value of a reference from an ArrayList of POJOs.
class OrderItem {
...
public List<Contact> getContacts() {
return contacts;
}
...
}
On a view, we want to be able to allow autoCompletes on multiple contacts per orderItem. The orderItem.contacts list is prepopulated with null placeholders by the time this is rendered:
<ui:repeat id="assignabilityContacts" value="#{orderItem.contacts}" var="_contact" varStatus="idx">
...
<p:autoComplete value="#{orderItem.contacts[idx.index]}"
id="existingContact"
binding="#{contactGroupManager.contactAutoComplete}"
converter="#{baseEntityConverter}"
completeMethod="#{contactGroupManager.autocomplete}"
forceSelection="true"
var="row" itemValue="#{row}" itemLabel="#{row.toString()}"
minQueryLength="2"
maxResults="10"
>
<f:attribute name="orderItem" value="#{orderItem}" />
</p:autoComplete>
The signature of the complete method is...
public List<Contact> autocomplete(Object suggest) {
}
And the converter follows Bauke Scholtz pattern for entities:
Implement converters for entities with Java Generics
As defined above, the value of orderItem.contacts[idx.index] is being set to a string, corresponding to the toString() of the selected pojo. The converter is never called.
If I change the value to a property of class Contact on another backing bean, the converter is called and the property is set to the selected Contact entity. This is the correct behavior.
value="#{contactSelector.selectedContact}"
Is it possible that autoConverter is not picking up the entity class from the List, and are there any suggested workarounds for this?

Related

How to set default value and label together for SelectOneMenu? [duplicate]

Is it possible to preselect one of the options from the select menu?
I have this UI Component:
<h:selectOneMenu value="#{authenticateController.country}">
<f:selectItems value="#{constants.countrySelectMenu}" />
</h:selectOneMenu>
The values of #{constants.countrySelectMenu} are a list of country ID - country name pairs.
Is there a way to render the list with a preselected value or at least is there a work-around to get this done?
Just preset the property behind <h:selectOneMenu value> with the desired value. You can do it in for example the bean's (post)constructor, action(listener) method, etc.
In your specific example, thus e.g.
public class AuthenticateController {
private String country;
#PostConstruct
public void init() {
country = "NL";
}
// ...
}
It works exactly the same way for all other UIInput components like <h:inputText> and so on. The input component's value itself simply represents the (pre)selected/checked/filled value.
See also:
How to populate options of h:selectOneMenu from database?

p:autoComplete shows entity Id after submit

I'm using Primefaces version 5.3 autocomplete in a web project, I have written the search method and converter for the java entities i am searching for. These all work well the selected entity from the autocomplete is set correctly in the backing bean using a p:ajax tab and initially the entity name, which i specify in the itemValue, is set in the text input.
When i then submit the form that includes this autocomplete the variable in the backing bean which i set from the autocomplete stays as it is which is intended but the text input on the autocomplete will display the entities id instead of the name as i'd specified on the itemValue. This is because it is calling the toString method in my converter but I want it still to display the name yet i need the converter..
Has anyone come across this issue that may be able to help?
I have found a thread else where that describe this behaviour but it is a couple years old now and doesn't have an answer.
This thread is:
http://forum.primefaces.org/viewtopic.php?f=8&t=37918
As it may explain it better than i have...
Any help is appreciated.
UPDATE: code added
Here is my autocomplete tag, complete method returns a java List of entity type.
<h:form>
<p:autoComplete id="autocomplete" value="#{bean.selectedEntity}"
completeMethod="#{bean.listOfPossibleEntities}"
itemValue="#{_e}" itemLabel="#{_e.name}" autocomplete="off"
minQueryLength="3" var="_e"
placeholder="Enter Entity Name Here"
converter="EntityConverter" forceSelection="true">
<p:ajax event="itemSelect" update="enclosingForm"/>
<p:column>
<h:outputText value="#{_e.name}" />
</p:column>
</p:autoComplete>
<p:commandButton update="#form" >
</h:form>
FacesConverter looks like as below, i use a DAO call to our database find the object for each id
private EntityDAO entityDAO = (EntityDAO)Component.getInstance("entityDAO");
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
Integer id = Integer.valueOf(value);
return entityDAO.findById(id,false);
}
#Override
public String getAsString(FacesContext fc, UIComponent uic, Object object) {
String result = "";
if(object != null) {
if(object instanceof Entity){
result = ""+ String.valueOf(((Entity) object).getEntityId());
}
}
return result;
}
So yes on update of the h:form after the entity on the autocomplete is selected and the submitting with the p:commandButton the value display or the entity will change from the entity name to the entity id.
Hope this helps further thanks.

<h:selectOneMenu> default value with id from other list [duplicate]

Is it possible to preselect one of the options from the select menu?
I have this UI Component:
<h:selectOneMenu value="#{authenticateController.country}">
<f:selectItems value="#{constants.countrySelectMenu}" />
</h:selectOneMenu>
The values of #{constants.countrySelectMenu} are a list of country ID - country name pairs.
Is there a way to render the list with a preselected value or at least is there a work-around to get this done?
Just preset the property behind <h:selectOneMenu value> with the desired value. You can do it in for example the bean's (post)constructor, action(listener) method, etc.
In your specific example, thus e.g.
public class AuthenticateController {
private String country;
#PostConstruct
public void init() {
country = "NL";
}
// ...
}
It works exactly the same way for all other UIInput components like <h:inputText> and so on. The input component's value itself simply represents the (pre)selected/checked/filled value.
See also:
How to populate options of h:selectOneMenu from database?

jsf working with collection/map

Can I bind my h:dataTable/rich:dataTable with some Map? I found that h:dataTable can work only with List object and deleting in List can be very heavy.
If you want to have only one method in your backing bean that provides the map, you can do something like this:
class Bean {
public Map<T,U> getMap() {
return yourMap;
}
}
and use this in your JSF view
<h:dataTable value="#{bean.map.keySet().toArray()}" var="key">
<h:outputText value="#{bean.map[key]}"/>
</h:dataTable>
This converts the key set into an array, which can be iterated by the datatable. Using the "()"-expression requires Unified Expression Language 2 (Java EE 6).
Yes, that's right. dataTable, ui:repeat and friends only work with Lists.
You can just add a managed bean method that puts map.keySet() or map.values() into a list depending on which you want to iterate over.
Typically when I want to iterate a map from a JSF view, I do something like
<h:dataTable value="#{bean.mapKeys}" var="key">
<h:outputText value="#{bean.map[key]}"/>
</h:dataTable>
with managed bean property
class Bean {
public List<T> mapKeys() {
return new ArrayList<T>(map.keySet());
}
}
or something like that.
Of course, this makes the most sense if you're using something like TreeMap or LinkedHashMap that preserves ordering.

Getting same instance of `componentType` in composite component on every use

Hi Have this Wierd Issue in which I am using a Composite Component which I wrote and I get values from the previous use of the backing bean of the CC (the componentType bean)
I don't know how to describe this better than just show the code.
I'll try to be brief about it and cut the redundant parts:
This is the Composite Component definition:
<cc:interface componentType="dynamicFieldGroupList">
<cc:attribute name="coupletClass" />
<cc:attribute name="form" default="#form"/>
<cc:attribute name="list" type="java.util.List" required="true"/>
<cc:attribute name="fieldNames" type="java.util.List" required="true" />
</cc:interface>
<cc:implementation>
<h:dataTable value="#{cc.model}" var="currLine">
<h:column>
<h:outputText id="inner_control_component" value="Inner Look at currLine:#{currLine}"/>
</h:column>
</h:dataTable>
</cc:implementation>
The CC bean defintion:
#FacesComponent(value = "dynamicFieldGroupList")
// To be specified in componentType attribute.
#SuppressWarnings({ "rawtypes", "unchecked" })
// We don't care about the actual model item type anyway.
public class DynamicFieldGroupList extends UIComponentBase implements
NamingContainer
{
private transient DataModel model;
#Override
public String getFamily()
{
return "javax.faces.NamingContainer"; // Important! Required for
// composite components.
}
public DataModel getModel()
{
if (model == null)
{
model = new ListDataModel(getList());
}
return model;
}
private List<Map<String, String>> getList()
{ // Don't make this method public! Ends otherwise in an infinite loop
// calling itself everytime.
return (List) getAttributes().get("list");
}
}
And the use code:
<ui:repeat var="group" value="#{currentContact.detailGroups}">
<h:panelGroup rendered="#{not empty group.values}">
<h:outputText id="controlMsg" value=" list:#{group.values}" /><br/><br/>
<utils:fieldTypeGroupList list="#{group.values}"
fieldNames="#{group.fields}" coupletClass="utils" />
</h:panelGroup>
</ui:repeat>
The text of id controlMsg displays the correct values in #{group.values} while the control output inside the component of id inner_control_component shows the values from the previous use.
The values are correct the first time...
I guess it's a fundemental error in use of a CC bean, otherwise it could be a bug with MyFaces 2.1 (Which I'm using)
The explanation for this behaviour is simple: there's only one component definied in the view. So there's also only one backing component with one model. Since the model is lazily loaded on first get, the same model is been reused in every iteration of a parent iterating component.
The <ui:repeat> doesn't run during view build time (as JSTL does), but during view render time. So there are physically not as many components in the view as items which are iterated by <ui:repeat>. If you were using <c:forEach> (or any other iteration tag which runs during view build time), then the composite component would have behaved as you'd expect.
You would like to change the way how the datamodel is kept in the backing component. You would like to preserve a separate datamodel for each iteration of a parent iterating component. One of the ways is to replace the model property as follows:
private Map<String, DataModel> models = new HashMap<String, DataModel>();
public DataModel getModel() {
DataModel model = models.get(getClientId());
if (model == null) {
model = models.put(getClientId(), new ListDataModel(getList()));
}
return model;
}
See also:
What's the view build time?
The problem described here is an old known isse in JSF, hidden by the usage of composite components. It is so important and so difficult, that instead answer here I create a detailed answer in a blog entry for this one: JSF component state per row for datatables
To keep this answer short, I'll say to you it is not a bug in MyFaces 2.1. Please use 2.1.1, because that is a quick bug fix version of 2.1.0. In JSF 2.1 there is a new property for h:dataTable called rowStatePreserved, and this scenario is just one case where "this little baby" becomes useful. Just replace ui:repeat with h:dataTable and add rowStatePreserved="true". That will do the trick. If you need to manipulate the model (add or remove rows) you can use tomahawk t:dataTable and t:dataList, but you will have to take an snapshot version for now. Note this is new stuff not available in any different JSF framework an the moment (JUN 2011).
If you need more info, keep tuned with MyFaces Team on Twitter or ask to the experts on MyFaces Users and Dev Mailing Lists.

Resources