How-to populate different select list content per table row
- by frank.nimphius
Normal
0
false
false
false
EN-US
X-NONE
X-NONE
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:"Table Normal";
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-qformat:yes;
mso-style-parent:"";
mso-padding-alt:0in 5.4pt 0in 5.4pt;
mso-para-margin:0in;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:11.0pt;
font-family:"Calibri","sans-serif";
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:"Times New Roman";
mso-fareast-theme-font:minor-fareast;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
A frequent requirement posted on the OTN forum is to render
cells of a table column using instances of af:selectOneChoices with each af:selectOneChoice instance
showing different list values.
To implement this use case, the select list of the table
column is populated dynamically from a managed bean for each row. The table's
current rendered row object is accessible in the managed bean using the #{row} expression, where
"row" is the value added to the table's var property.
<af:table var="row">
...
<af:column ...>
<af:selectOneChoice ...>
<f:selectItems
value="#{browseBean.items}"/>
</af:selectOneChoice>
</af:column
</af:table>
The browseBean
managed bean referenced in the code snippet above has a setItems and getItems
method defined that is accessible from EL using the #{browseBean.items} expression.
When the table renders, then the var property variable - the #{row} reference - is filled with the
data object displayed in the current rendered table row.
The managed bean getItems method returns a List<SelectItem>, which is the model
format expected by the f:selectItems
tag to populate the af:selectOneChoice
list.
public void setItems(ArrayList<SelectItem> items) {} //this method is executed for each table row
public ArrayList<SelectItem> getItems() {
FacesContext fctx = FacesContext.getCurrentInstance();
ELContext elctx = fctx.getELContext();
ExpressionFactory efactory =
fctx.getApplication().getExpressionFactory();
ValueExpression ve =
efactory.createValueExpression(elctx, "#{row}", Object.class); Row rw = (Row) ve.getValue(elctx); //use one of the row attributes to determine which list to query and //show in the current af:selectOneChoice list // ... ArrayList<SelectItem> alsi = new ArrayList<SelectItem>(); for( ... ){ SelectItem item = new SelectItem(); item.setLabel(...); item.setValue(...); alsi.add(item); } return alsi;}
For better performance, the ADF Faces table stamps it data
rows. Stamping means that the cell renderer component - af:selectOneChoice in this example -
is instantiated once for the column and then repeatedly used to display the
cell data for individual table rows. This however means that you cannot refresh
a single select one choice component in a table to change its list values.
Instead the whole table needs to be refreshed, rerunning the managed bean list
query.
Be aware that having individual list values per table row
is an expensive operation that should be used only on small tables for Business
Services with low latency data fetching (e.g. ADF Business Components and EJB) and
with server side caching strategies for the queried data (e.g. storing queried
list data in a managed bean in session scope).