p:autoComplete binding not showing label for searched value - jsf

I am trying to generate autocomplete box through binding. But I am not sure why label for the searched value is not rendered on UI. Code snippet is added below. Please help.
FacesContext facesContext = FacesContext.getCurrentInstance();
AutoComplete autoComplete = new AutoComplete();
ExpressionFactory factory = ExpressionFactory.newInstance();
#SuppressWarnings("rawtypes")
Class[] classes = new Class[1];
classes[0] = User.class;
autoComplete.setCompleteMethod(factory.createMethodExpression(facesContext.getELContext(), "#{userBean.values}", List.class , classes));
autoComplete.setVar("user");
autoComplete.setDropdown(false);
autoComplete.setItemValue(facesContext.getApplication().getExpressionFactory().createValueExpression("#{user}", User.class));
autoComplete.setItemLabel(facesContext.getApplication().evaluateExpressionGet(facesContext, "#{user.name}", String.class));
autoComplete.setConverter(new CommonConvertor());

I end up writing custom renderer in which wherever ItemLabel is referred I overridden the method & instead of using ItemLabel directly I put the EL expression evaluation whenever I find ItemLabel is starting with "#{". Which resulted in proper working of an autocomplete. The solution works.
I have overridden below methods
encodeInput
encodeMultipleMarkup
encodeSuggestionsAsTable
encodeSuggestionsAsList
Please let me know if you can find easier solution.

Related

PrimeFaces datatable default sortBy from backing bean

I have a data table with a POJO object:
<p:dataTable id="table" var="object" sortBy="#{object.name}" sortOrder="DESCENDING">
object has fields id, name, date, size for example. I am able to set default sort field using xhtml, but I want set it from backing bean.
I am able to parse column id when user creates sort request for example name.
public void sortEventListener(AjaxBehaviorEvent actionEvent) {
String id = ((SortEvent) actionEvent).getSortColumn().getColumnKey();
String[] idPath = id.split(":");
sortBy = idPath[idPath.length - 1];
sortOrder = ((SortEvent) actionEvent).isAscending();
}
My task detects which column user wants to sort and persists it to db. After reload the data table should be sorted by this column.
When I set
sortBy="#{bean.sortBy}" // sortBy = name
it's not working and data table is not sorted after rendering the page.
Please help.
If you bind your data table to a org.primefaces.component.datatable.DataTable object in your bean or find the table component in your bean, you can use the table object to set the sortBy value expression programmatically.
To get an idea how PrimeFaces is handling sorting, you can have a look at the source code at GitHub.
When you have the sort column, you can easily get the sort value expression. So, in your listener you could use something like:
UIColumn sortColumn = sortEvent.getSortColumn();
ValueExpression sortByVE = sortColumn.getValueExpression("sortBy");
By the way, you can replace the parameter type AjaxBehaviorEvent with SortEvent in your sort listener method.
Now, store the sortByVE expression, and set it as the sortBy value expression of the bound table when needed:
dataTable.setValueExpression("sortBy", sortByVE);
If you want to create the value expression from scratch, use something like:
FacesContext context = FacesContext.getCurrentInstance();
ExpressionFactory ef = context.getApplication().getExpressionFactory();
ValueExpression ve = ef.createValueExpression(context.getELContext(),
"#{object.name}",
Object.class);
dataTable.setValueExpression("sortBy", ve);
In this example "#{object.name}" is fixed. You should construct it based on the value you get from your sort listener.
If you want to find your table in your bean, OmniFaces Components might be helpful. It also offers a shortcut method to create value expressions.
See also:
How does the 'binding' attribute work in JSF? When and how should it be used?
Programmatically getting UIComponents of a JSF view in bean's constructor
How do I set the value of HtmlOutputTag in JSF?

dynamic dataTable and sortBy not working

I'm using primefaces and dataTable (lazy mode) and i need generate definition of dataTables on fly / in code. I'm able to build dataTable, columns, labels, values, ... but sorting not working.
I tried:
column.setSortBy("name"); // where name is name of property/column
column.setSortBy("#{row['name']}"); // where row is map and name is name of property/column - this is what im using in XML version and it working very well
column.setSortBy(ef.createValueExpression(context, "#{row['name']}", Object.class));
DataTable looks like with disabled sorting (no arrows at labels)...
When i have definition in XML then everything works fine (it's not about lazyDataModel or anything else in model layer).
Try this code
FacesContext context = FacesContext.getCurrentInstance();
ExpressionFactory expressionFactory = context.getApplication().getExpressionFactory();
ValueExpression valueExpression = expressionFactory.createValueExpression(context.getELContext(), "#{row['name']}", String.class);
column.setValueExpression("sortBy", valueExpression);
where I used String.class because i supposed that "#{row['name']}" evaluates to an instance of the class String.

Create and add f:selectItems to HtmlSelectOneRadio programmatically

I'm using JSF to create a questionnaire and therefore I need to create my whole xhtml pragmatically because there are different types of questions and the number of them is not predefined.
All I have is a h:panelGrid on my view and the rest is generated in my backing bean.
I have no problem creating HtmlOutputText and HtmlInputText. For that purpose I create them using getApplication e.g. like this:
getApplication().createComponent(HtmlOutputText.COMPONENT_TYPE);
and then add the component to my grid like this:
grid.getChildren().add(questionnumber);
where "grid" is my panelGrid element.
So I put my questions in a loop and based on the type of question from the db I decide what type of component to create. If the question is a normal text question I can easily use a HtmlInputText. But I have multiple choice questions too. Therefore I need to create SelectOneRadio menus and add SelectItems in them.
I can create a HtmlSelectOneRadio using the same createComponent method that I mentioned above. But I'm unable to add options to it (selectitem components). Is there a way that I can do this? Do we have a UIComponent for this that I am missing?
I found the solution myself. I had to use UISelectItems and add it to my SelectOneMenu like this:
final UISelectItem select = (UISelectItem) getApplication().createComponent(UISelectItem.COMPONENT_TYPE);
List<SelectItem> items = new ArrayList<SelectItem>();
for (int k = 0; k < options.length; k++){
items.add(new SelectItem(options[k]));
}
UISelectItems selectItems = new UISelectItems();
selectItems.setValue(items);
selectOneRadio.getChildren().add(selectItems);
grid.getChildren().add(selectOneRadio);

Is this a bug in primefaces autocomplete?

I'm trying to put an autocomplete that fetches suggestions as a list of Entry<String, Integer>
<p:autoComplete completeMethod="#{suggester.suggestTopics}"
var="x1" itemLabel="#{x1.key}" itemValue="#{x1.value.toString()}"
value="#{topicController.selected}" />
Manged bean code is as follows:
private int selected;
public int getSelected() {
return selected;
}
public void setSelected(int selected) {
this.selected= selected;
}
But this fails saying the Integer class doesn't have method/property named key. If I remove the value attribute from autocomplete then it starts working properly. But when I put value attribute it starts expecting that the object inside var should be of the same type as that inside value attribute. I believe/expect it should be that the object inside itemValue should be of the same type as that inside value attribute.
I want to use POJOs for suggestions but pass just the entity Id to the value
Using :
Primefaces 3.1
JSF 2.1.6
I believe/expect it should be that the object inside itemValue should
be of the same type as that inside value attribute.
Yes this makes sense, and it is the same in the primefaces showcase:
<p:autoComplete value="#{autoCompleteBean.selectedPlayer1}"
id="basicPojo"
completeMethod="#{autoCompleteBean.completePlayer}"
var="p" itemLabel="#{p.name}" itemValue="#{p}"
converter="player" forceSelection="true"/>
As you see is var="p" and itemValue="#{p} where p is an instance of Player. And selectedPlayer1 is also an instance of Player.
I don't know if it works with a Map since the Primefaces example is called "Pojo support" and the suggestions should be a List of elements of the same type as in the value attribute.
I think you want to use the Simple auto complete , but instead you looked at the wrong example on the showcase of the Pojo Support
x1 refers to the int selected - while it expect to be referred to a POJO (with key and value properties.) , that's why you get the message
Integer class doesn't have method/property named key
Or simple use the Simple auto complete
As commented to Matt you dont need to rebuild Player(Pojo) from Db. You can set simply id property of Player(Pojo) and in action method may be utilize this id to fetch it from DB.
In your case in convertor you might do
Entry<String, Integer> e = new Entry<String, Integer>();
e.setId(value) // where value is passed in to convertor in method getAsObject.....
This value will be set to private Entry<String, Integer> selected
I have used Pojo autocomplete but not tried with generic classes.
Hope this helps.
I know the question is outdated but I've had the same problem.
The point is that you have to assign var to p (var="p"). I think it's terribly unobvious (documentation doesnot mention it has to be that way) 'cause I thought I can assign any var name I want.

"ValueExpression Map" of a JSF component

I'm storing value expressions in a JSF component with the f:attribute tag, e.g.:
<h:inputText ...>
<f:attribute name="myId1" value="#{bean.prop1}" />
<f:attribute name="myId2" value="#{bean.prop2}" />
<f:attribute name="myId3" value="#{bean.prop3}" />
</h:inputText>
Is there a way to access all of those value expressions programmatically? (without knowlegde of the names myId1, myId2,...)
Section 9.4.2 of the JSF 2.1 specification says that those values are stored "in the component’s ValueExpression Map".
That's the only occurrence of the term "ValueExpression Map" in the complete spec.
How do I access that map?
In the UIcomponent's Method getValueExpression() of the Jboss/Mojarra implementation the map
getStateHelper().get(UIComponentBase.PropertyKeys.bindings)
is used to obtain a single value expression.
I guess that map is a super set of the "ValueExpression Map"?
Can I be sure that all implementations and all inherited (standard) components use that map to store ValueExpressions?
Thanks.
In theory you should be able to see them all by UIComponent#getAttributes():
Map<String, Object> attributes = component.getAttributes();
for (Map.Entry<String, Object> entry : attributes.entrySet()) {
System.out.printf("name=%s, value=%s%n", entry.getKey(), entry.getValue());
}
However, that doesn't work the way as you'd expect. It only returns static attributes. This does not seem to ever going to be fixed/implemented. See also JSF issue 636. I'd suggest to stick to attribtues with predefinied prefix and an incremental numerical suffix, like as you've presented in your example. That's also what I've always used to pass additional information from the component on to custom validators and converters. You can just collect them as follows:
Map<String, Object> attributes = component.getAttributes();
List<Object> values = new ArrayList<Object>();
for (int i = 1; i < Integer.MAX_VALUE; i++) {
Object value = attributes.get("myId" + i);
if (value == null) break;
values.add(value);
}
System.out.println(values);
An alternative to the answer given by BalusC might be to use nested facets or UIParameter components. Facets can be retrieved as a map using getFacets but you probably need to put an additional UIOutput inside each facet to access its value expression.
Nested UIParameters can be accessed by iterating over the components children and checking for instanceof UIParameter. UIParameters have name and value attributes and so could be easily converted to a map.
I have used parameters in a custom component, but I'm not sure how a standard UIInput like in your example reacts to these.
BalusC is right. UIComponent#getAttributes().get(name) gets values from both places - at first from attributes map and then if not found from "value expression map". To put some value you have to call UIComponent#setValueExpression(name, ValueExpression). If value is literal, it gets stored into the attribute map, otherwise into the "value expression map". Everything is ok then.

Resources