How to override h:selectOneRadio renderer? Where is the renderer class in jsf-impl?

前端 未结 2 916
囚心锁ツ
囚心锁ツ 2020-12-04 02:37

Is it possible to override renderer used by ? I tried to find the class from jsf-impl package of JSF 2.2 but didn\'t find it. The reason

相关标签:
2条回答
  • 2020-12-04 02:41

    I added

      <render-kit>
            <renderer>
                <component-family>javax.faces.SelectOne</component-family>
                <renderer-type>javax.faces.Radio</renderer-type>
                <renderer-class>com.sial.ecommerce.configurator.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 need.

    0 讨论(0)
  • 2020-12-04 03:03

    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.

    Consider looking at Tomahawk or PrimeFaces instead of reinventing the wheel. They have respectively a <t:selectOneRadio layout="spread"><t:radio> and <p:selectOneRadio layout="custom"><p:radioButton> which allows you positioning those things everywhere you want.

    See also:

    • <h:selectOneRadio> renders table element, how to avoid this?
    0 讨论(0)
提交回复
热议问题