UIData - building a dataTable row-by-row
Hi,
I need to create a dataTable with a dynamic number of columns, so am trying to bind the table with a backing bean property, like so:
<h:dataTable border="1"
styleClass="tables"
rowClasses="rows"
id="roleGroups"
binding="#{jobTitleFormBean.roleGroupsTable}"
value="#{jobTitleFormBean.tableRows}"
var="row"
/>
In the backing bean (jobTitleFormBean), the method getRoleGroupsTable() builds the UIData object representing the table and returns it.
Each column represents a role group, which contains a number of roles. The number of rows in the table should be equal to the total number of possible roles, as each cell in a column will indicate whether the role is contained in that role group. So I need each cell in the table to contain an 'tick' image, which is only rendered if the role is in the role group.
So I add a UIGraphic as a child of each UIColumn (only one column used for now):
public UIData getRoleGroupsTable()
{
this.roleGroupsTable = new UIData();
UIColumn column = new UIColumn();
UIGraphic tickImage = new UIGraphic();
tickImage.setUrl("images/tick.gif");
tickImage.setRendererType("javax.faces.Image");
//TODO: set whether tick is to be rendered
column.getChildren().add(tickImage);
this.roleGroupsTable.getChildren().add(column);
return this.roleGroupsTable;
}
The question is how to specify whether the tick image is rendered. The method setRendered() on the UIGraphic takes a boolean parameter, but I can't think how to evaluate this, as it needs to be evaluated row-by-row. I'm not sure how I can reference a row of the table from there.
Any ideas?
As a follow-up, I have made the tableRows property of jobTitleFormBean an ArrayDataModel. Each row of data is a List of Booleans. In building the UIData table, I attempt to get the current row of data as follows:
List<Boolean> booleans = (List<Boolean>)this.tableRows.getRowData();
I then set the rendered attribute on the tick image from the list:
boolean rendered = booleans.get(i);
tickImage.setRendered(rendered);
where i is the index of the current column. However, it's not working. In debugging through it, the above code only seems to be called once for each column. I expected it to be called for each row of each column.
Does anyone know of a way to make this work...?
There are - I think - often a lot of possible solutions...
One solution - not very nice - would be to inherit from UIGraphic and to override isRendered.
the rowIndex could be get from the parent of the parent... as we know this is a UIData Element:
see the principle here:
public boolean isRendered() {
logger.info("Entering graph is rendered");
// return super.isRendered();
UIData u = (UIData)getParent().getParent();
logger.info("ROW INDEX = "+u.getRowIndex());
if (u.getRowIndex() % 2 == 0) return true;
else return false;
}
but it's really ugly...
Forget the first solution - it's really ugly.
Another - quite much better - solution is to use a value binding with the rendered attribute.
Create a bean holding the values of the rows and a boolean to indicate if the image has to be rendered or not.
The table is just an array (or ArrayList) of these beans. Using the var attribute You simply access the different properties.
Take care that the getter of the boolean property is a getXXX method, not isXXX.
public class TableBean {
private Stringdata;
private boolean enabled;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean getEnabled()
{
return enabled;
}
}
...
public TableBinding getRoleGroupsTable() {
roleGroupsTable = new TableBinding();
UIColumn column = new UIColumn();
UIGraphic tickImage = new UIGraphic();
HtmlOutputText out = new HtmlOutputText();
UIColumn c2 = new UIColumn();
out.setValueBinding("value", FacesContext.getCurrentInstance().getApplication().createValueBinding("#{row.data}"));
c2.getChildren().add(out);
tickImage.setUrl("images/plus.gif");
tickImage.setRendererType("javax.faces.Image");
tickImage.setValueBinding("rendered", FacesContext.getCurrentInstance().getApplication().createValueBinding("#{row.enabled}"));
// TODO: set whether tick is to be rendered
column.getChildren().add(tickImage);
roleGroupsTable.getChildren().add(c2);
roleGroupsTable.getChildren().add(column);
return roleGroupsTable;
}
Hi dcoder,
Thanks for your advice, I've been off-line the last 3 days.....
What exactly is a TableBinding, and how do I bind it to the display table? At the moment I have:
<h:dataTable border="1"
styleClass="tables"
rowClasses="rows"
id="roleGroups"
binding="#{jobTitleFormBean.roleGroupsTable}"
value="#{jobTitleFormBean.tableRows}"
var="row"
/>
where roleGroupsTable was a UIData object. Will it work with a TableBinding instead?