hitesh israni
hitesh israni

Reputation: 1752

JSF SelectMany check boxes, binding to sub lists

I am using SelectMany Checkboxes of primefaces and facing some trouble in storing the values in the Bean.

I need an array of SelectManyCheck boxes. Here is the xhtml so far,

<c:set var="obj" value="#{userBean.userSettingsMap}"> </c:set>
<c:forEach items="#{obj}" var="entry">
  <h:outputText value="#{entry.key} " /><!--Correctly prints the key -->
  <p:selectManyCheckbox value="#{entry.value}"><!-- `entry.value` SHOULD correspond to inner lists --->
    <!-- I want values of these check boxes to be updated in my ManagedBean's property -->
    <f:selectItem itemLabel="Option 1" itemValue="Option 1" />
    <f:selectItem itemLabel="Option 2" itemValue="Option 2" />
    <f:selectItem itemLabel="Option 3" itemValue="Option 3" />
</p:selectManyCheckbox>
</c:forEach>   

The Array of Select Many check boxes is rendered on the page. But when i submit the page, the sub-list is not updated. rather the object in my ManagedBean is not getting updated.

So, on submit i get blank lists displayed on the dialog.

{key 1=[], key 2=[]}

In my ManagedBean i have,

  private Map<String,List<String>> userSettingsMap; 

Where the sub-lists would correspond to the each <p:selectManyCheckbox> on the view

Submit button is the same as in the examples.

  <p:commandButton value="Submit" update="display" oncomplete="dlg.show()" />
    <p:dialog header="Selected Values" modal="true" showEffect="fade" hideEffect="fade" widgetVar="dlg">

      <p:outputPanel id="display">
          <p:dataList value="#{userService.userMaintainceMap}" var="option">
              #{option}
          </p:dataList>             
      </p:outputPanel>

Upvotes: 2

Views: 2666

Answers (1)

Arjan Tijms
Arjan Tijms

Reputation: 38163

You iterate over your Map using the JSTL's c:forEach, which means every entry will be an internal iterator type that's most likely an implementation of Map.Entry (e.g. MappedValueExpression.Entry). There is a setValue method here, but it doesn't confirm to the JavaBeans conventions, meaning EL won't find it.

As a result #{entry.value} will be seen as a read-only property and <p:selectManyCheckbox> will not be able to store its value there. I would expect an exception to appear, but perhaps it's swallowed somewhere. A normal form and a normal command button would definitely trigger an exception here.

A second issue is that you have a Map with generics as the target of your selection, but EL will not be able to see those generics (blame the notorious lack of reified generics in Java), and will thus specifically not see the value is a List. It will then put a String[] instance in your map.

If you use your Map expression indexed by its key as the target for your selection AND declare the Map to be typed to String[], your code should work.

E.g.

innercheckbox.xhtml:

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:c="http://java.sun.com/jsp/jstl/core"
    xmlns:p="http://primefaces.org/ui">

    <h:body>

        <h:form>
            <c:forEach items="#{innerCheckboxBacking.userSettingsMap}" var="entry">
                <h:outputText value="#{entry.key}" />
                <p:selectManyCheckbox value="#{innerCheckboxBacking.userSettingsMap[entry.key]}">
                    <f:selectItem itemLabel="Option 1" itemValue="Option 1" />
                    <f:selectItem itemLabel="Option 2" itemValue="Option 2" />
                    <f:selectItem itemLabel="Option 3" itemValue="Option 3" />
                </p:selectManyCheckbox>
            </c:forEach>

            <h:commandButton value="Submit" action="#{innerCheckboxBacking.action}" />

        </h:form>

    </h:body>
</html>

InnerCheckboxBacking.java:

@ManagedBean
@ViewScoped
public class InnerCheckboxBacking {

    private Map<String, String[]> userSettingsMap = new LinkedHashMap<>();

    @PostConstruct
    public void init() {
        userSettingsMap.put("key1", null);
        userSettingsMap.put("key2", null);
    }

    public void action() {
        String[] result = userSettingsMap.get("key1");
        for (String string : result) {
            System.out.println(string);
        }
    }

    public Map<String, String[]> getUserSettingsMap() {
        return userSettingsMap;
    }

}

Upvotes: 3

Related Questions