开发者

JSF: How to bind many of h:selectBooleanCheckbox?

I have a problem to bind list of h:selectBooleanCheckbox to my bean. Anybody helps ?

This is not working:

<ui:repeat value="#{cartBean.productsList}" var="cartProduct" varStatus="i">
   <h:selectBooleanCheckbox binding="#{cartBean.checkboxes[i.index]}" />
</ui:repeat>

public class CartBean extends BaseBean {
  public List<Product> getProducts开发者_Go百科List() {...}

  private HtmlSelectBooleanCheckbox[] checkboxes;
  public HtmlSelectBooleanCheckbox[] getCheckboxes() {
    return checkboxes;
  }
  public void setCheckboxes(HtmlSelectBooleanCheckbox[] checkboxes) {
    this.checkboxes = checkboxes;
  }
}

I get error:

javax.faces.FacesException: javax.el.PropertyNotFoundException: /WEB-INF/flows/main/cart.xhtml @26,97 binding="#{cartBean.checkboxes[i.index]}": Target Unreachable, 'checkboxes' returned null

I solved my problem. I used code like below and get what i want (thanks to BalusC blog - http://balusc.blogspot.com/2006/06/using-datatables.html#SelectMultipleRows):

<ui:repeat value="#{cartBean.productsList}" var="cartProduct" varStatus="i">
  <h:selectBooleanCheckbox value="#{cartBean.selectedIds[cartProduct.id]}" />
</ui:repeat>

public class CartBean extends BaseBean {
  private Map<Integer, Boolean> selectedIds = new HashMap<Integer, Boolean>();
  public Map<Integer, Boolean> getSelectedIds() {
    return selectedIds;
  }
}


Your concrete problem is caused because the binding attribute is evaluated during view build time, that moment when the XHTML source code is turned into a JSF UI component tree, while the <ui:repeat> runs during view render time, that moment when the JSF UI component tree needs to produce HTML.

In other words, the #{i.index} is only available during view render time and evaluates as null during view build time. In effects, you're doing a binding="#{cartBean.checkboxes[null]}"

There's another conceptual mistake here: you seem to expect that the <ui:repeat> produces physically multiple <h:selectBooleanCheckbox> components. This is untrue. There's physically only one <h:selectBooleanCheckbox> which is reused multiple times to produce HTML based on the currently iterated variable. Actually, binding="#{cartBean.checkbox}" was been sufficient. However, collecting the values is a story apart. I won't go in detail, but you can find several hints in this answer: Validate order of items inside ui:repeat.

In order to achieve the (apparent) concrete functional requirement of generating physically multiple <h:selectBooleanCheckbox> components and binding each to a separate array item, you should be using an iteration component which runs during view build time instead of view render time. That's the JSTL <c:forEach>:

<c:forEach items="#{cartBean.productsList}" var="cartProduct" varStatus="i">
    <h:selectBooleanCheckbox binding="#{cartBean.checkboxes[i.index]}" />
</c:forEach>

But, after all, using binding on a bean property should be avoided as much as possible. Use instead exactly that attribute which you ultimately need: the value attribute. This way you don't need to do a HtmlSelectBooleanCheckbox#getValue() everytime. You already figured the right solution with a Map<Integer, Boolean> selectedIds:

<ui:repeat value="#{cartBean.productsList}" var="cartProduct">
    <h:selectBooleanCheckbox value="#{cartBean.selectedIds[cartProduct.id]}" />
</ui:repeat>

See also:

  • JSTL in JSF2 Facelets... makes sense?


I don't know if you can bind elements stored in an array. But in your code, the problem is that your HtmlSelectBooleanCheckbox[] is null. So maybe change your Java code to:

public HtmlSelectBooleanCheckbox[] getCheckboxes() {
    if (checkboxes == null) {
        checkboxes = new HtmlSelectBooleanCheckbox[getProductsList().size()];
    }
    return checkboxes;
}

but I am really not sure if it will work... Maybe the solution is to not bind your HtmlSelectBooleanCheckbox elements in the Java code. Why do you need to bind them?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜