What's the correct way to have a boolean checkbox in a JSF / RichFaces `dataTable` database?

What is the correct way to have a boolean checkbox on every line in JSF / RichFaces dataTable

? I tried the following snippet:

<rich:dataTable id="customerList"
               var="_customer"
             value="#{customerList.resultList}"
          rendered="#{not empty customerList.resultList}" >
    <h:column>
        <h:selectBooleanCheckbox
            value="#{customerList.selectedCustomers[_customer.id]}" />
    </h:column>
...
</rich:dataTable>

      

I set mine customerList

to have Map<Integer, Boolean> selectedCustomers

. Everything seems to work well, except that apparently the checkbox is matched by the sorting index, not the ID, which is giving me a problem.

For example, when I open the page above and check the box on the first line and click the Delete button, everything works fine and the page reloads without the client selected. But if I click "Refresh" or "Reload", then (and accept the browser warning about forwarding the data), the client that is currently on the first line will be deleted!

What if the checkbox is bound only to the selected identifier?

+2


source to share


1 answer


If you want to handle the update, see the setting redirect

in the navigation rules.

  <navigation-rule>
    <display-name>navBack</display-name>
    <from-view-id>/navBack.jsp</from-view-id>
    <navigation-case>
      <from-outcome>navTo</from-outcome>
      <to-view-id>/navTo.jsp</to-view-id>
      <redirect />
    </navigation-case>
  </navigation-rule>

      

If you want to handle a back button and multiple windowed windows, read on.

You can detect this using hidden field and line level artifact. Basically, you are checking the ID sent to the client against the ID you received when the form was submitted.

public class SafeRow {
  private final String rowId;
  private String rowIdClient;
  private String name;
  private boolean delete;

  public SafeRow(String name) {
    this();
    this.name = name;
  }

  public SafeRow() {
    rowId = UUID.randomUUID().toString();
  }

  public String getRowId() { return rowId; }    
  public void setRowId(String rowIdClient) { this.rowIdClient = rowIdClient; }

  public boolean isStateConsistent() {
    return rowId.equals(rowIdClient);
  }

  public String getName() { return name; }
  public void setName(String name) { this.name = name; }

  public boolean isDelete() { return delete; }
  public void setDelete(boolean delete) { this.delete = delete; }
}

      



Table data:

public class SafeUpdateBean {
  private final List<SafeRow> data = new ArrayList<SafeRow>();

  public SafeUpdateBean() {
    data.add(new SafeRow("Bill"));
    data.add(new SafeRow("Ben"));
    data.add(new SafeRow("Sue"));
  }

  public List<SafeRow> getData() { return data; }

  public String deleteSelected() {
    Iterator<SafeRow> all = data.iterator();
    while (all.hasNext()) {
      SafeRow row = all.next();
      if (!row.isStateConsistent()) {
        System.err.println("Caught inconsistency on " + row.getRowId());
      } else if (row.isDelete()) {
        all.remove();
      }
    }
    return null;
  }
}

      

View:

<h:form>
  <h:dataTable value="#{safeUpdateBean.data}" var="row">
    <h:column>
      <h:inputHidden value="#{row.rowId}" />
      <h:selectBooleanCheckbox value="#{row.delete}" />
      <h:outputText value="#{row.name}" />
    </h:column>
  </h:dataTable>
  <h:commandButton value="delete selected"
    action="#{safeUpdateBean.deleteSelected}" />
</h:form>

      

This demo code uses a simple session bean, but hopefully it's clear how you could adapt it to something more sane. This is not the only thing you could do - for example, you could make a more general copy of the form as duplicates. Third party frameworks like Seam add handling for this sort of thing as well.

+3


source







All Articles