1 Reply Latest reply on Dec 20, 2011 3:11 PM by Christian Peter

    Unable to select a row in a datatable

    Jordi Torrente Newbie

      Using 4.1 final release I'm trying to allow "row selection" for a datatable. So, I started with:

       

      <rich:dataTable value="#{selectBackingBean.dataModel}" width="100%" var="dataItem" id="theList" rows="5"

      onrowmouseover="this.style.backgroundColor='#F1F1F1'"

      onrowmouseout="this.style.backgroundColor='#{a4jSkin.tableBackgroundColor}'">

       

      <a4j:ajax event="rowclick" listener="#{selectBackingBean.selectionListener}" render="selectiontable"/>

       

      The datamodel used extends org.ajax4jsf.model.ExtendedDataModel<E> and its "getRowKey()" does not rely on the elements position and uses a property of the parametrized class (f.e. clientId)

       

      With this configuration every attempt to process the selection event fails because the datamodel is unable to fetch the selected row's data. I've found out that the problem is the "key" received through the method "setRowKey(Object key)": the code expects a custom one (f.e. clientId) but the value received is the row position

       

      Details

       

      1) When rendering a <rich:dataTable> component, each of its rows gets an "id" generated using the table "id" and the row position. Look at the following code (org.richfaces.renderkit.AbstractTableBaseRenderer):

       

      public void encodeRowStart(ResponseWriter writer, FacesContext context, String parentId, int currentRow, UIComponent component) throws IOException {

          writer.startElement(HtmlConstants.TR_ELEMENT, component);

          writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, parentId + ":" + currentRow, null);

       

          String styleClass = concatClasses(getRowClass(context, parentId), component.getAttributes().get(ROW_CLASS));

          if (styleClass.length() > 0) {

              writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, styleClass, null);

          }

      }

       

      For example: <tr id="j_idt38:theList:3" class="rf-dt-r" ...

       

       

      2) org.richfaces.renderkit.DataTableRenderer processes the event inside the method doDecode(FacesContext context, final UIComponent component). As you can see, this method retrieves the  "id" generated during previous encoding and passes it to UIDataAdaptor.invokeOnRow method:

       

      String behaviorSourceId = RenderKitUtils.getBehaviorSourceId(context);

       

      ((UIDataAdaptor) component).invokeOnRow(context, behaviorSourceId, new ContextCallback() {

      ...

      }

       

       

      3) And inside UIDataAdaptor.invokeOnRow:

       

      String baseId = getClientId(context);

      ...

      String rowId = clientId.substring(baseId.length() + 1);

      ...

      if (rowId != null) {

          Converter keyConverter = getRowKeyConverter();

       

          if (null != keyConverter) {

              try {

                  newRowKey = keyConverter.getAsObject(context, this, rowId);

              } catch (ConverterException e) {

                  LOG.warn(e);

              }

          }

      }

       

      setRowKey(context, newRowKey);

       

      (keyConverter is an IntegerConverter instance)

       

      So, the key for the selected row is set to its position on the current page. This implementation only works when  "row key = row position" and no pagination is used, or.... Am I wrong?

       

      Thanks in advance

      Jordi