tags:

views:

527

answers:

1

How to attach a rich:tooltip to the list generated by f:selectItems when using a variable for the attribute for inside the rich:tooltip.

This code works fine (the value of #{prefix} is theprefixvalue

<ui:composition>
<a4j:form id="#{prefix}_form">
<h:selectOneRadio style="text-align:left" id="#{prefix}_rating">
<f:selectItems value="#{test.options}"></f:selectItems>
</h:selectOneRadio>&nbsp; 
<rich:toolTip for="theprefixvalue_form\:theprefixvalue_rating\:0">a</rich:toolTip>      
</a4j:form>
</ui:composition>

But this code does not:

<ui:composition>
<h:outputText value="#{prefix}" />
<a4j:form id="#{prefix}_form">
<h:selectOneRadio style="text-align:left" id="#{prefix}_rating">
<f:selectItems value="#{test.options}"></f:selectItems>
</h:selectOneRadio>&nbsp; 
<rich:toolTip for="#{prefix}_form\:#{prefix}_rating\:0">a</rich:toolTip>        
</a4j:form>
</ui:composition>

Throws the following exception:

Caused by: java.lang.IllegalArgumentException: theprefixvalue_rating
    at javax.faces.component.UIComponentBase.findComponent(UIComponentBase.java:612)
    at org.ajax4jsf.renderkit.RendererUtils.findComponentFor(RendererUtils.java:1037)
    at org.richfaces.renderkit.html.ToolTipRenderer.getTargetId(ToolTipRenderer.java:234)
    at org.richfaces.renderkit.html.ToolTipRenderer.constructJSVariable(ToolTipRenderer.java:251)
...

TestBean is session scoped and this is the code for getOptions();

public List<SelectItem> getOptions(){
    List<SelectItem> options = new ArrayList<SelectItem>();
    options.add(new SelectItem("a","a"));
    options.add(new SelectItem("b","b"));
    options.add(new SelectItem("c","c"));
    return options;

}

Any ideas? The goal is to have a tooltip when the mouse is over the different options. Thanks in advance.

Edit: Apparently HtmlSelectOneRadio is not implementing NamingContainer, so it fails at UIComponentBase line 611: (result is an instance of HtmlSelectOneRadio, length>0 and segments[1] = "theprefixvalue_rating")

        if (result != null && (!(result instanceof NamingContainer)) && length > 0) {
            throw new IllegalArgumentException(segments[i]);

I am trying to use my own NamedHtmlSelectOneRadio which extends HtmlSelectOneRadio and implements NamingContainer but I'm still guessing how to inject it with facelets. Any idea?

+1  A: 

Finally I managed to solve it.

I created my own component called NamedHtmlSelectOneRadio which is just a wrapper of HtmlSelectOneRadio but implements NamingContainer. I don't know if this will have further implications through the rest of JSF code, but my testcase works fine. Anyway, I'll update this answer if I find any strange behavior, as well as I'll post in the Mojarra implementation of JSF regarding why HtmlSelectOneRadio does not implements NamingContainer out-of-the-box.

Here are the steps to create your own component with facelets.

1 Wrap the class:

import javax.faces.component.NamingContainer; import javax.faces.component.html.HtmlSelectOneRadio;

public class NamedHtmlSelectOneRadio extends HtmlSelectOneRadio implements NamingContainer {

    public NamedHtmlSelectOneRadio(){
        super();
    }

}

2 Wrap the Tag class and set the above class as component Type:

import com.sun.faces.taglib.html_basic.SelectOneRadioTag;

public class NamedHtmlSelectOneRadioTag extends SelectOneRadioTag {

    public NamedHtmlSelectOneRadioTag(){
        super();
    }
    @Override
    public String getComponentType() {
        return "javax.faces.NamedHtmlSelectOneRadio";
    }

}

3 Add the component to your faces-config.xml configuration:

<component>
<component-type> com.eyeprevent.util.NamedHtmlSelectOneRadio </component-type>
<component-class> com.eyeprevent.util.NamedHtmlSelectOneRadio </component-class>
</component>

4 Add the tag to your taglib (mine is functions.taglib.xml). More info about creating your own taglib here

<tag>
<tag-name>namedSelectOneRadio</tag-name>
<component>
<component-type>com.eyeprevent.util.NamedHtmlSelectOneRadio</component-type>
</component>
</tag>`

5 Include the new taglib in your .xhtml (or .jsf) page and replace the h:selectOneRadio with your own (mine is fnc:namedSelectOneRadio)

xmlns:fnc="http://eyeprevent.com/fnc"
...

<fnc:namedSelectOneRadio id="#{prefix}_rating">
<f:selectItems value="#{test.options}"></f:selectItems>
</fnc:namedSelectOneRadio>
<rich:toolTip for="#{prefix}_form\:#{prefix}_rating:0">a</rich:toolTip>

And that's all!

pakore