jsfhtml-tableselectoneradio

<h:selectOneRadio> renders table element, how to avoid this?


Is there a way to tell JSF that it should NOT render a <table> element when using <h:selectOneRadio>? I don't use tables and it makes absolutely no sense in this case.

Any help is appreciated!


Solution

  • JSF 2.3 with group attribute

    As per JSF spec issue 329 I have added a new group attribute to <h:selectOneRadio> which should make this all much less tedious. All radio button components having the same group value within a parent UIForm will be grouped with each other. Also they won't render any markup besides the radio button itself and the optional label if the select item has a non-null label. If any, the label appears directly after the radio button.

    <!-- Just markup them the way you want! -->
    <ul>
        <ui:repeat id="items" value="#{bean.items}" var="item">
            <li>
                <h:selectOneRadio group="foo" value="#{bean.selectedItem}">
                    <f:selectItem itemValue="#{item}" />
                </h:selectOneRadio>
            </li>
        </ui:repeat>
    </ul>
    

    Following scenarios are also possible. When there are multiple components with same group, and the value attribute and/or UISelectItem child is absent, then it will reference those of the first component of the group.

    <h:selectOneRadio group="foo" value="#{bean.selectedItem}">
        <f:selectItems value="#{bean.availableItems}" />
    </h:selectOneRadio>
    <h:selectOneRadio group="foo" />
    <h:selectOneRadio group="foo" />
    
    <h:selectOneRadio group="foo" value="#{bean.selectedItem}">
        <f:selectItem itemValue="one" />
        <f:selectItem itemValue="two" />
        <f:selectItem itemValue="three" />
    </h:selectOneRadio>
    <h:selectOneRadio group="foo" />
    <h:selectOneRadio group="foo" />
    
    <h:selectOneRadio group="foo" value="#{bean.selectedItem}">
        <f:selectItem itemValue="one" />
    </h:selectOneRadio>
    <h:selectOneRadio group="foo">
        <f:selectItem itemValue="two" />
    </h:selectOneRadio>
    <h:selectOneRadio group="foo">
        <f:selectItem itemValue="three" />
    </h:selectOneRadio>
    
    <h:selectOneRadio group="foo" value="#{bean.selectedItem}">
        <f:selectItem itemValue="one" />
    </h:selectOneRadio>
    <h:selectOneRadio group="foo" value="#{otherBean.selectedItem}">
        <f:selectItem itemValue="two" />
    </h:selectOneRadio>
    <h:selectOneRadio group="foo" value="#{lastBean.selectedItem}">
        <f:selectItem itemValue="three" />
    </h:selectOneRadio>
    

    It will be available in Mojarra as per 2.3.0-m07.

    JSF 2.2 with passthrough elements

    If you're on JSF 2.2 already, make use of its new passthrough elements/attribtues feature whereby you explicitly set the name attribute as a passthrough attribute. In order to set the submitted value in the model, you only need an additional <h:inputHidden>.

    <html xmlns="http://www.w3.org/1999/xhtml"
          xmlns:jsf="http://xmlns.jcp.org/jsf"
          xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
          xmlns:a="http://xmlns.jcp.org/jsf/passthrough">
    
    ...
    
    <!-- Just markup them the way you want! -->
    <ul>
        <ui:repeat id="items" value="#{bean.items}" var="item">
            <li>
                <input type="radio" jsf:id="item" a:name="#{hiddenItem.clientId}"
                    value="#{item}" a:checked="#{item eq bean.selectedItem ? 'checked' : null}" />
                <h:outputLabel for="item" value="#{item}" />
            </li>
        </ui:repeat>
    </ul>
    
    <!-- This one won't display anything. -->
    <h:inputHidden id="selectedItem" binding="#{hiddenItem}" value="#{bean.selectedItem}"
        rendered="#{facesContext.currentPhaseId.ordinal ne 6}" />
    

    In depth technical explanation can be found in this blog: Custom layout with h:selectOneRadio in JSF 2.2.

    PrimeFaces (JSF 2.x)

    If you happen to use PrimeFaces, then you can also use <p:selectOneRadio layout="custom"> with <p:radioButton>.

    <html ... xmlns:p="http://primefaces.org/ui">
    
    <!-- This one won't display anything. -->
    <p:selectOneRadio id="foo" value="#{bean.selectedFoo}" layout="custom">
        <f:selectItems value="#{bean.availableFoos}" />
    </p:selectOneRadio>
    
    <!-- Just markup them the way you want! -->
    <ul>
        <li><p:radioButton for="foo" itemIndex="0" /></li>
        <li><p:radioButton for="foo" itemIndex="1" /></li>
        <li><p:radioButton for="foo" itemIndex="2" /></li>
    </ul>
    

    You can also loop over the available items, you only need to do it during view build time:

    <ul>
        <c:forEach items="#{bean.availableFoos}" varStatus="loop">
            <li><p:radioButton for="foo" itemIndex="#{loop.index}" /></li>
        </c:forEach>
    </ul>
    

    Tomahawk (JSF 1.x or 2.x)

    If you're not on JSF 2.2 yet or if you don't like PrimeFaces UI, grab Tomahawk's <t:selectOneRadio> which renders the same plain HTML output as <h:selectOneRadio>, but supports a layout="spread" attribute so that you can position the items by <t:radio> the way you want.

    E.g.

    <html ... xmlns:t="http://myfaces.apache.org/tomahawk">
    
    <!-- This one won't display anything. -->
    <t:selectOneRadio id="foo" value="#{bean.selectedFoo}" layout="spread">
        <f:selectItems value="#{bean.availableFoos}" />
    </t:selectOneRadio>
    
    <!-- Just markup them the way you want! -->
    <ul>
        <li><t:radio for="foo" index="0" /></li>
        <li><t:radio for="foo" index="1" /></li>
        <li><t:radio for="foo" index="2" /></li>
    </ul>
    

    Custom Renderer

    Supply a custom Renderer. It's only a bit of work. Start at the first "See also" link shown below:

    See also: