5

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.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Mahmoud Saleh
  • 33,303
  • 119
  • 337
  • 498

3 Answers3

21

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;
}
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • when i use `` inside the `h:selectOneRadio` so that the `valueChangeListener` work, the radio button gets selected then unselected, any ideas ? i want the selected radio to be kept selected, and the old selected to be unselected – Mahmoud Saleh Jun 10 '12 at 15:18
  • There's no need for `` here. – BalusC Jun 10 '12 at 16:16
  • the valueChangeListener is not fired when i click on any radio button. – Mahmoud Saleh Jun 10 '12 at 16:17
  • can you please have a look at this approach too http://stackoverflow.com/questions/10970248/hselectbooleancheckbox-doesnt-get-checked-when-the-value-is-true – Mahmoud Saleh Jun 10 '12 at 16:18
  • 2
    That's also not the intent. It's fired only when you submit the form the usual way by a command button. Or do you want to submit the form immediately when a radio button is selected? You didn't ask for that. That way the whole JavaScript workaround is unnecessary and the answer has to be changed. – BalusC Jun 10 '12 at 16:22
  • i tried it now, and it works very fine, and i am able to catch the object and save it into database, but there's still one issue, is that i want to set a selected object programmatically in the preRender, how to do that ? – Mahmoud Saleh Jun 11 '12 at 08:50
  • ,i tried JS solution but seems JS won't help here since there might be a paginator in this datatable, any ideas ? – Mahmoud Saleh Jun 11 '12 at 12:08
  • @BalusC This code is really helpful however I'm not very well versed with JSF ...can you please explain "value="#{bean.items}" var="item". what does value and var contain – Twaha Mehmood Feb 12 '16 at 05:24
0

i found another solution, and i want to share it with you, is to use the h:selectBooleanCheckbox, along with the single selection JS function BalusC suggested:

            <ace:column id="homePage" headerText="Home Page">
                <h:selectBooleanCheckbox value="#{adpage.homePage}" onclick="dataTableSelectOneRadio(this);"></h:selectBooleanCheckbox>
            </ace:column>

and the JS:

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;
    }

this will check only one checkbox and update the boolean property in the checked/unchecked object.

Mahmoud Saleh
  • 33,303
  • 119
  • 337
  • 498
  • 1
    Checkboxes are however more confusing in UI perspective when used as single selection as they normally indicate multiple selection. You shouldn't use this for single selection. If your sole intent is to preserve a selected/checked value, just use the `value` attribute and a proper `` value. How to use `` properly is already been answered here: http://stackoverflow.com/questions/2524514/how-to-use-jsfs-hselectbooleancheckbox-with-hdatatable-to-create-one-object-p/2524832#2524832 – BalusC Jun 11 '12 at 14:41
0

selectedRadioButton variable should be declared out of the function.

var selectedRadioButton;

function uncheckRadioButtons(radioButton) {
   if (selectedRadioButton != null) {
      selectedRadioButton.checked = false;
   }

   selectedRadioButton = radioButton;
   selectedRadioButton.checked = true;
}

and in xhtml

 <h:selectOneRadio 
        onclick="uncheckRadioButtons(this);">
        <f:selectItem itemValue="null" />
    </h:selectOneRadio>
Surya
  • 416
  • 4
  • 7
  • 26