Sometimes one wants to update some cells of a table using AJAX. Re-render the whole table is mostly not an option ,especially if the table(s) are very large. Using the Richfaces framework it’s quite simply.

This may be the JSF code:

...
<rich:subTable value="#{myBackingBean.descriptions}" var="oneTableRow" border="0" id="monatsberichtValuesSubTable" 
ajaxKeys="#{myBackingBean.rowsToUpdate}" rowKeyVar="rowCounter">
    <rich:column styleClass="#{oneTableRow.styleClass}">
        <h:outputLink value="#{oneTableRow.linkTarget}">
            <h:outputText value="#{oneTableRow.linkName}"/>
        </h:outputLink>
    </rich:column>
    <rich:column styleClass="#{oneTableRow.styleClass}">
        <h:outputText value="#{oneTableRow.description}"/>
    </rich:column>
    <rich:columns value="#{myBackingBean.getArrayWithFieldValues(oneTableRow.mappedToValuesRowId)}" var="field" 
    border="0" index ="ind3" styleClass="#{field.getStyleClass()}" colspan="#{field.getColspan()}">
        <h:inputText value="#{field.fieldIntegerValue}" ondblclick="setErgebnisCalculator(this)" 
    rendered="#{field.showField and (!myBackingBean.reportClosed) and (myBackingBean.writePermission) and (field.editable)}">
            <a4j:support event="onchange" ajaxSingle="true" reRender="id_0,id_1,id_2,id_3,id_4,id_5,id_6" 
            action="#{myBackingBean.calculateSums(0, oneTableRow.mappedToValuesRowId, ind3)}"/>
        </h:inputText>
        <h:outputText value="#{field.fieldIntegerValue}" id="#{field.identifier}" 
        rendered="#{field.showField and (!field.editable or myBackingBean.reportClosed or !myBackingBean.writePermission )}"/>
    </rich:columns>
</rich:subTable>    
...

The subTable uses the ajaxKeys attribute and the tag uses the reRender attribute. Used together they act like coordinates for the X-axis and Y-axis inside the table.

The backing - or more specific the method called by the AJAX request - looks like that:

...
private Set<Integer> rowsToUpdate = new HashSet<Integer>();
...
public String calculateSums(int tableNumber, int rowNumber, int columnNumber) throws BusinessException{
    log.debug("calculateSums() called for table number: " + tableNumber + " and row numer " +
     rowNumber + " and column number " + columnNumber + "...");
    /* Just call the internal calculation method */
    calculateInternal(...);
    /* Add the last row (holding the sums) to the set of rows which should be updated */
    rowsToUpdate.add(reportTables[0].getDescriptions().length-1);
    rowsToUpdate.add(rowNumber);
    return "";
}
...
public Set<Integer> getRowsToUpdate() {
    return rowsToUpdate;
}