4

Is it possible to override renderer used by <h:selectOneRadio>? I tried to find the class from jsf-impl package of JSF 2.2 but didn't find it. The reason I want to do this is to get rid of the table it generates.

2 Answers 2

4

Is it possible to override renderer used by h:selectOneRadio?

Yes, surely it is. Otherwise, UI component libraries like PrimeFaces couldn't exist.


I tried to find the class from jsf-impl package but didn't find it.

The exact class depends on the JSF implementation you're using. If it's Mojarra, then it's the com.sun.faces.renderkit.html_basic.RadioRenderer class. If it's MyFaces, then it's the org.apache.myfaces.renderkit.html.HtmlRadioRenderer class.

In order to properly override it, just extend the class and override methods where necessary and register it as follows in your faces-config.xml:

<render-kit> <renderer> <component-family>javax.faces.SelectOne</component-family> <renderer-type>javax.faces.Radio</renderer-type> <renderer-class>com.example.MyRadioRenderer</renderer-class> </renderer> </render-kit> 

Keep in mind that you're this way tight-coupling the renderer to the specific JSF impl/version. Such an extended renderer is not compatible with a different JSF implementation (i.e. your app wouldn't deploy when you ever replace Mojarra by MyFaces) and may possibly break when the current JSF implementation has been updated to a newer version. If you worry about this, consider writing the renderer entirely from scratch, like PrimeFaces et.al. do.


The reason I want to do this is to get rid of the table it generates.

Just upgrade to a minimum of JSF 2.3. See also <h:selectOneRadio> renders table element, how to avoid this?

Sign up to request clarification or add additional context in comments.

Comments

1

I added

 <render-kit> <renderer> <component-family>javax.faces.SelectOne</component-family> <renderer-type>javax.faces.Radio</renderer-type> <renderer-class>com.path.ui.model.RadioRendererWithoutDataTable</renderer-class> </renderer> </render-kit> 

to faces-config.xml.

And created a class which extends com.sun.faces.renderkit.html_basic.RadioRenderer And I did override the method encodeEnd then commented out the code which adding table elements.

public class RadioRendererWithoutDataTable extends com.sun.faces.renderkit.html_basic.RadioRenderer { @Override public void encodeEnd(FacesContext context, UIComponent component) throws IOException { rendererParamsNotNull(context, component); if (!shouldEncode(component)) { return; } ResponseWriter writer = context.getResponseWriter(); assert (writer != null); String alignStr; Object borderObj; boolean alignVertical = false; int border = 0; if (null != (alignStr = (String) component.getAttributes().get("layout"))) { alignVertical = alignStr.equalsIgnoreCase("pageDirection"); } if (null != (borderObj = component.getAttributes().get("border"))) { border = (Integer) borderObj; } Converter converter = null; if (component instanceof ValueHolder) { converter = ((ValueHolder) component).getConverter(); } // renderBeginText(component, border, alignVertical, context, true); Iterator<SelectItem> items = RenderKitUtils.getSelectItems(context, component); Object currentSelections = getCurrentSelectedValues(component); Object[] submittedValues = getSubmittedSelectedValues(component); Map<String, Object> attributes = component.getAttributes(); OptionComponentInfo optionInfo = new OptionComponentInfo((String) attributes.get("disabledClass"), (String) attributes.get("enabledClass"), (String) attributes.get("unselectedClass"), (String) attributes.get("selectedClass"), Util.componentIsDisabled(component), isHideNoSelection(component)); int idx = -1; while (items.hasNext()) { SelectItem curItem = items.next(); idx++; // If we come across a group of options, render them as a nested // table. if (curItem instanceof SelectItemGroup) { // write out the label for the group. if (curItem.getLabel() != null) { // if (alignVertical) { // writer.startElement("tr", component); // } //writer.startElement("td", component); writer.writeText(curItem.getLabel(), component, "label"); // writer.endElement("td"); // if (alignVertical) { // writer.endElement("tr"); // } } // if (alignVertical) { // writer.startElement("tr", component); // } // writer.startElement("td", component); // writer.writeText("\n", component, null); // renderBeginText(component, 0, alignVertical, context, false); // render options of this group. SelectItem[] itemsArray = ((SelectItemGroup) curItem).getSelectItems(); for (int i = 0; i < itemsArray.length; ++i) { renderOption(context, component, converter, itemsArray[i], currentSelections, submittedValues, alignVertical, i, optionInfo); } // renderEndText(component, alignVertical, context); // writer.endElement("td"); // if (alignVertical) { // writer.endElement("tr"); // writer.writeText("\n", component, null); // } } else { renderOption(context, component, converter, curItem, currentSelections, submittedValues, alignVertical, idx, optionInfo); } } //renderEndText(component, alignVertical, context); } 

Then it worked for me.

When I given

<h:selectOneRadio > <f:selectItem itemValue="1" itemLabel="Item 1" /> <f:selectItem itemValue="2" itemLabel="Item 2" /> </h:selectOneRadio> 

in my jsf page.

It converted to

<input type="radio" name="bulkForm:j_idt224" id="bulkForm:j_idt224:0" value="1"><label for="bulkForm:j_idt224:0"> Item 1</label> <input type="radio" name="bulkForm:j_idt224" id="bulkForm:j_idt224:1" value="2"><label for="bulkForm:j_idt224:1"> Item 2</label> 

which was what I needed.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.