The existing solution does not strike me as a bad one. The rowIndex should work in nested tables so long as you're referencing the model of the nested table.
<h:dataTable border="1" value="#{nestedDataModel}" var="nested">
<h:column>
<h:dataTable border="1" value="#{nested}" var="item">
<h:column>
<h:outputText value="#{nested.rowIndex}" />
</h:column>
<h:column>
<h:outputText value="#{item}" />
</h:column>
</h:dataTable>
</h:column>
</h:dataTable>
Sample model:
public class NestedDataModel extends DataModel implements Serializable {
private List<List<String>> nestedDataModel = populateModel();
private int index;
private List<List<String>> populateModel() {
List<List<String>> list = new ArrayList<List<String>>();
for(int x=0; x<3; x++) {
List<String> nestedTableData = new ArrayList<String>();
for(int y=0; y<3; y++) {
nestedTableData.add("Foo x="+x+" y="+y);
}
list.add(nestedTableData);
}
return list;
}
@Override
public int getRowCount() {
return nestedDataModel.size();
}
@Override
public Object getRowData() {
List<String> list = nestedDataModel.get(index);
return new ListDataModel(list);
}
@Override
public int getRowIndex() {
return index;
}
@Override
public Object getWrappedData() {
return nestedDataModel;
}
@Override
public boolean isRowAvailable() {
return index >= 0 && index < nestedDataModel.size();
}
@Override
public void setRowIndex(int arg0) {
index = arg0;
}
@Override
public void setWrappedData(Object arg0) {
throw new UnsupportedOperationException();
}
}
Nesting dataTables should generally be avoided - if you're not careful (e.g. make them children of a form), this can lead to a O(N^2) pass over the table children for each phase of the lifecycle on a submit (and there are 6 phases in the lifecycle).
For something that is external to the model, you could use a simple counter in a managed bean:
public class RowCounter implements Serializable {
private transient int row = 0;
public int getRow() {
return ++row;
}
}
Config:
<managed-bean>
<managed-bean-name>rowCounter</managed-bean-name>
<managed-bean-class>tablerows.RowCounter</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
View:
<f:view>
<h:dataTable border="1" value="#{tableDataBean.tableDataModel}"
var="rowBean">
<h:column>
<h:outputText value="#{rowCounter.row}" />
</h:column>
<h:column>
<h:outputText value="#{rowBean}" />
</h:column>
</h:dataTable>
</f:view>
This works because the bean is request-scope and bound to a read-only control outside a form. It would not work in a nested dataTable unless you wanted the row counter to be global to the view. But then, I'm not convinced that the row index should be a function of the view.
For a nested dataTable, you would be better off providing the row index from the row bean. It gives you more control if you decide to do things like pagination over data sets too.