PrimeFaces datatable default sortBy from backing bean - jsf

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?

Related

How to fill a JSF/Primefaces DataTable from a ManagedBean?

I'm realizing my first application using JSF2 and Primefaces 5 .
I want that when the user press a button my managed bean creates a new DataTable and fill it with some data. How can I do that from my managed bean?
This is a part of code of my managed bean.
...
//This is the managed bean's method executed when the user presses the button.
public void execute() {
...
//Get the data from database and put the entries in a list of java beans called myList.
//Here I create a ListDataModel to convert myList in a DataModel to pass to the datatable
ListDataModel<myJavaBean> tableData = new ListDataModel<myJavaBean>(myList);
//Then I create a new datatable..
DataTable dataTable = new DataTable();
//.. and I set the data
dataTable.setValue(tableData);
//I define the columns
Column idColumn = new Column();
idColumn.setHeaderText("id");
Column dateColumn = new Column();
dateColumn.setHeaderText("date");
Column timeColumn = new Column();
timeColumn.setHeaderText("time");
Column stateColumn = new Column();
stateColumn.setHeaderText("state");
//Here I add the columns to the table
dataTable.getChildren().add(idColumn);
dataTable.getChildren().add(dateColumn);
dataTable.getChildren().add(timeColumn);
dataTable.getChildren().add(stateColumn);
...
When I press the button this part of code create a new DataTable with the correct number of columns and the correct header.
Also the number of row is correct but the row are completely empty, I suppose this is due to the fact that I have not bound the Columns with the respective java bean properties of the list. How can I do that?
So you want to create a UI component from a managed bean ???
Maybe I'm missing something here, but a proper and simpler way to acheive this is that the Datatable must be declared in facelet (your_page.hxtml) using <p:datatable> and link it to a backing bean containing the data (i.e. value="#{yourbean.yourlist}").
On startup, your backing bean can be empty. You just have to render UI differently, whether your data is loaded or not (see the "rendered" tag on the datatable component).
Just fill data into the bean when you have to do it (button/execute).
And do not forget to update UI parts (see "update" tag on your action button) in order to refresh altered page regions (datatable at least).
example:
<p:datatable id="mytable" var="child" value="#{mybean.children}" rendered="#{not empty mybean.children}">
...
</p:datatable>
...
<p:button update="mytable">
...

Is it possible to use custom JSF converter for UISelectOne, depending on value of Bean property or UIInputText value?

I need to get help with a problem.
I have an application, which displays data from database.
In database I am using one column for identifying an object with changes in time (version of object).
I mean that rows have different IDs, but same OBJECT_ID.
They are also differentiated by validity DATE columns (VALID_FROM and VALID_TO), so i can find the proper version of object in selected time.
When page is shown to user, he sets DATE for displaying data.
There is form on page, with Select Boxes (their items are object from database).
I need to show only items, that satisfy the validity condition.
Everything is OK before form handling.
I am using custom converter, that converts String value (ID of row in database table) to Object of my model, but I need two values for row to find. (ID and DATE from user form).
Converter method getAsObject gets only one VALUE parameter (ID from Select Box).
How to get second parametr to work?
Can i find it from Bean or from JSF input object?
If there is some way that includes using <f:attribute/>, is there way to set <f:attribute/> by Java code in Bean? (Form is generated by bean method).
I am sorry for my English, i try my best :o)
P.S.: Date parameter is important in sqlMap because of JOIN used. I search by ID, but other tables are joined by OBJECT_ID (version) => and i need to get one row only
Thanks for answers and have a nice day
Worsik
Edit:
Select Boxes are generated by this code:
uiInput = new HtmlSelectOneMenu();
UISelectItems items = new UISelectItems();
items.setValueExpression("value", createValueExpression(
"#{myBean.referencedList." + item.getName() + "}",
List.class));
uiInput.getChildren().add(items);
Converter method looks like this:
public Object getAsObject(FacesContext context, UIComponent component, String value)
{
if (value.equals("")) {
return null;
}
Class entityType = component.getValueExpression("value").getType(
FacesContext.getCurrentInstance().getELContext());
// TODO: need to get date value from form
Date day = new Date();
return myService(context).findEntityById(entityType, Long.valueOf(value), day);
}
entityType is Class of model for object from database
myService calls Dao object and sqlMap is called
select * from object_table as t1
JOIN other_table as t2 ON t1.object_fk = t2.object_id // (or version_id)
where t1.id = #id:INTEGER#
and t2.valid_from <= #day:DATE#
and t2.valid_to >= #day:DATE#
I figured out how to do this by <f:attribute/> by code in converter:
Date day = (Date) component.getAttributes().get("dateForSearch");
and in bean method after generating SelectBox with code:
uiInput.getAttributes().put("dateForSearch", getSelectedDate());
and in pages without dynamic generating of forms i used:
<SelectOneMenu>
...
<f:attribute name="dateForSearch" value="#{myBean.selectedDate}" />
</SelectOneMenu>
I hope that this will not be only self answered question and will help somebody else

IceFaces selectInputDate value changes after getting data

I have an ice:selectInputDate but the value of the component is not the same as in the backing bean. I have to select two different dates to successfully update the variable value of the backing bean.
What am I missing?
What I want to do is to populate a table after getting some data from the DB with the date as a filter.
You should post some code to get a better idea. Are you using a valueChangeListener and partialSubmit? If so, if you set the variable in the listener it would be the same in the bean as soon as you select the inputDate.
You can populate the table from the listener
for example:
public void dateListener(ValueChangeEvent evt){
yourDate = (Date) evt.getNewValue();
//get your data for the table
}

"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.

How to create commandlink programmatically

We have a system built on seam/richfaces.
There's this webpage where the tables are rendered from dynamic context (from multiple different datasources, and each of them uses a different layout to represent essentially the same real world concept). As a result, this table is binded to a bean, and it's columns/layout are generated from this bean.
Now I need to add a command link on a specific column, equivalent to
<a4j:commandLink value="#{actBean.Ids}" action="#{actBean.genDetails}">
<f:setPropertyActionListener target="#{actBean.Ref}" value="#{cont}"/>
</a4j:commandLink>
in a JSF page.
The table is binded to a managed bean with
HtmlDataTable dataTable = new HtmlDataTable();
HtmlColumn column = new Column();
//some code to setup column name, value etcs
dataTable.getChildren().add(column);
//What do I do here to bind a commandlink with a property action
//listener to column?
My question is, how do I do this programmatically?
Thanks!
HtmlAjaxCommandLink commandLink = new HtmlAjaxCommandLink();
commandLink.addActionListener(new SetPropertyActionListener(target, value));
column.getChildren().add(commandLink);
where target and value are ValueExpression's. These can be created with:
ExpressionFactory.getInstance().createValueExpression(ctx, expression, expectedType)
And the required ELContext can be obained via FacesContext.getCurrentContext().getELContext()

Resources