jsfjsf-2datatableselectoneradio

How to use h:selectOneRadio in h:dataTable to select single row?


I have list of pages displayed in table. Each page has property homePage and I want in the datatable to have a column of radio buttons to be binded on this property, and the user can only check one value. How can I get this value on server side?

I saw some examples like the following: http://jforum.icesoft.org/JForum/posts/list/14157.page, but I would like to know what is the best practice in such case.


Solution

  • As per JSF spec issue 329 I have finally implemented it for JSF 2.3. With the new group attribute you will now be able to group radio buttons in a repeater component.

    <h:dataTable value="#{bean.items}" var="item">
        <h:column>
            <h:selectOneRadio group="foo" value="#{bean.selectedItem}">
                <f:selectItem itemValue="#{item}" />
            </h:selectOneRadio>
        </h:column>
    </h:dataTable>
    

    It will be available as per Mojarra 2.3.0-m07.


    Before JSF 2.3, this is not trivial with standard JSF <h:selectOneRadio>. Basically, the radio button in every row needs to be grouped with each other using the same input name so that the other radio buttons get unchecked whenever you select one. But they are not been grouped, they have all their own name, so the other radio buttons would never be unchecked.

    Component libraries like PrimeFaces have solved it by providing a special attribute or column component. See also this showcase example which uses a <p:column selectionMode="single"> to generate a single selection column. The selected value is referenced by selection attribute of <p:dataTable>. If you're already using a component library and it has already such a component for you, you should use it.

    In standard JSF <h:dataTable> with <h:selectOneRadio> you'd need to bring in a JavaScript workaround as follows which unchecks all other radio buttons in the same column:

    <h:dataTable value="#{bean.items}" var="item">
        <h:column>
            <h:selectOneRadio valueChangeListener="#{bean.setSelectedItem}"
                onclick="dataTableSelectOneRadio(this);">
                <f:selectItem itemValue="null" />
            </h:selectOneRadio>
        </h:column>
        ...
    </h:dataTable>
    

    with

    public void setSelectedItem(ValueChangeEvent event) {
        FacesContext context = FacesContext.getCurrentInstance();
        selectedItem = context.getApplication().evaluateExpressionGet(context, "#{item}", Item.class);
    }
    

    and

    function dataTableSelectOneRadio(radio) {
        var radioId = radio.name.substring(radio.name.lastIndexOf(':'));
    
        for (var i = 0; i < radio.form.elements.length; i++) {
            var element = radio.form.elements[i];
    
            if (element.name.substring(element.name.lastIndexOf(':')) == radioId) {
                element.checked = false;
            }
        }
    
        radio.checked = true;
    }