How to create commandlink programmatically - jsf

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()

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?

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

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
}

Bind the value of an input component to a list item by index

here is an example :
<h:outputLabel for="category1" value="Cateogry"/>
<h:selectOneMenu id ="category1" value="#{articleManageBean.categoryId1}"
converter="categoryConverter">
<f:selectItems value="#{articleManageBean.categories}" var="category"
itemValue="#{category.id}" itemLabel="#{category.name}" />
</h:selectOneMenu>
and here is the managed bean that I have
#ManagedBean
#SessionScoped
public class ArticleManageBean {
private Long categoryId1;
private List<Category> categories;
//...
}
The categories list gets populated from db, and selectOneMenu gets populated with this list using a converter.
My First question:
If I want to create another selectOneMenu in my jsf page I would have to copy paste the entire thing and just change the value of selectOneMenu to say categoryId2 thus putting another attribute to managed bean called categoryId2. That is not practical. I want to map these values of selectMenu to list items, for instance to an attribute
List<Long> categoryIds;
if I use
<h:selectOneMenu id ="category1" value="#{articleManageBean.categoryIds.[0]}" >
I get an error
javax.el.PropertyNotFoundException: /createArticle.xhtml #47,68 value="#{articleManageBean.categoriesId[0]}": Target Unreachable, 'null' returned null
If I nitialize the Araylist then I get this exception
javax.el.PropertyNotFoundException: /createArticle.xhtml #47,68 value="#{articleManageBean.categoriesId[0]}": null
My second question:
Is there a way to dinamicly write selectOneMenu tags, by that I mean not to copy paste the entire tag, just somehow create a function that take the categoryId parameter and writes automaticaly the tag (somekind of custom tag maybe ?)
Hope you understood my questions
thanks in advance
Use the brace notation instead to specify the index.
<h:selectOneMenu id="category1" value="#{articleManageBean.categoryIds[0]}">
You only need to make sure that you have already prepared the values behind #{articleManageBean.categoryIds}. JSF won't do that for you. E.g.
private List<Long> categoryIds = new ArrayList<Long>();
public ArticleManageBean() {
categoryIds.add(null);
categoryIds.add(null);
categoryIds.add(null);
// So, now there are 3 items preserved.
}
an alternative is to use Long[] instead, this doesn't need to be prefilled.
private Long[] categoryIds = new Long[3]; // So, now there are 3 items preserved.

How do I bind a inputbox values to a map value in a backing bean property when using a wizard

I am using the Primefaces wizard component. On one tab I am dynamically creating input boxes based on previous tabs input(user type). The inputbox text labels are derived from a list. In my backing bean, I have a map that contains input labels as keys and inputbox inputs as values.
Clicking on next, I would like the map(values) to be updated with the user input (corresponding to the key)
<c:forEach items="#{gdsiGeodataBean.actionCommand.fields}" var="reqs">
<h:outputLabel for="#{reqs.name}" value="#{reqs.name}:* " />
<pou:inputText value="#{gdsiGeodataBean.actionCommand.values['reqs.name']}" required="true" requiredMessage="Input is required."/>
</c:forEach>
My backing bean :
private List<RequiredParam> fields; // +getter (no setter required)
private Map<String, String> values; // +getter (no setter required)
public CommandAction(String actionName, String actionParams, String context) {
this.actionName = actionName;
this.actionParams = actionParams;
this.contextName = context;
//Set up parameters
getRequiredParams();
getOptionalParams();
fields = getFields();
values = new HashMap<String, String>();
}
Essentially what I would like is for the map values to be updated with user inputs from the textinput boxes.
Your approach to bind the input value to a map is not entirely correct.
<pou:inputText value="#{gdsiGeodataBean.actionCommand.values['reqs.name']}" required="true" requiredMessage="Input is required."/>
You're specifying a fixed map key instead of a dynamic map key based on the currently iterated #{reqs}. This way all submitted values will end up in one and same fixed map key "reqs.name", whereby each one overrides each other so that you only get the value of the last field in the map.
You need to remove those singlequotes to make it a really dynamic key.
<pou:inputText value="#{gdsiGeodataBean.actionCommand.values[reqs.name]}" required="true" requiredMessage="Input is required."/>
Unrelated to the concrete question, even though this approach will work when used as-is in your question, the <c:forEach> will fail in certain circumstances. E.g. when used inside a composite component or an iterating JSF component. Rather use <ui:repeat> instead. See also JSTL in JSF2 Facelets... makes sense?

Resources