1

I've been trying to create a custom ui component for jsf to replace <f:selectItems />, which is wrapped in a selectOneMenu. So my facesComponent needs to generate all the options while the selectOneMenu provides the <select></select>.

Problem is that the options are not rendered inside the selectOneMenu, but rather just outside of it.

My facesComponent looks like this:

@FacesComponent(value = "be.mokuril.jsf.SelectItemsForEnum")
public class SelectItemsForEnum extends UISelectItems {

@Override
public void encodeAll(FacesContext facesContext) throws IOException {
    ResponseWriter responseWriter = ResponsefacesContext.getResponseWriter();
    responseWriter.startElement("option", null);
    responseWriter.writeAttribute("value", 1, null);
    responseWriter.write("option1");
    responseWriter.endElement("option");
    responseWriter.startElement("option", null);
    responseWriter.writeAttribute("value", 2, null);
    responseWriter.write("option2");
    responseWriter.endElement("option");
}

And this is my taglib:

<facelet-taglib xmlns="http://java.sun.com/xml/ns/javaee" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
version="2.0" id="mw"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd" 
>
<namespace>http://www.mokuril.be/jsf/mw</namespace>
<composite-library-name>mw</composite-library-name>

<tag>
    <tag-name>selectItemsForEnum</tag-name>
    <component>
        <component-type>be.mokuril.jsf.SelectItemsForEnum</component-type>
    </component>
</tag>

And the xhtml to reproduce the problem:

<h:form>
 <h:selectOneMenu>
    <mw:selectItemsForEnum />
 </h:selectOneMenu>
</h:form>

I've also been looking at the component tree:

<HtmlSelectOneMenu disabled="false" id="j_idt7" immediate="false" inView="true" localValueSet="false" readonly="false" rendered="true" required="false" transient="false" valid="true">
  <SelectItemsForEnum id="j_idt8" inView="true" rendered="true"  transient="false"/>
</HtmlSelectOneMenu>

And if I use <f:selectItems /> instead of my component I get this:

<UISelectItems id="j_idt9" inView="true" rendered="true" transient="false"/>

Which is actually what I expected it to look like, but I clearly must be overlooking something important.

mokuril
  • 742
  • 2
  • 9
  • 14

1 Answers1

1

Your concrete problem is caused because UISelectOne/UISelectMany components will scan their direct children for UISelectItem(s) instences. When you use a composite component, its content is basically wrapped in an UIPanel component, which is not an instance of UISelectItem(s), so the selection components will ignore it. Technically, you should be using a custom component instead of a composite component. See also When to use <ui:include>, tag files, composite components and/or custom components?

However, you'll stumble upon the next problem: the UISelectOne/UISelectMany will continue to render the options all by themselves and ignore the output from your renderer. Basically, no one <f:xxx> component renders HTML by itselves. This responsibility is up to its <h:xxx> parent. Technically, you should be overriding the renderer of <h:selectOneMenu> instead if you want to manipulate the output of <f:selectItem(s)>.

It's unclear which problem you're trying to solve this way, but if I were to do educated guesses, those questions should most probably answer and solve your real problem the correct way: How to use enum values in f:selectItem(s) and/or How to add tooltip to f:selectItems.

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • The goal is to provide a tag for selectItems where you only need to specify an ID. Then the component will use that ID to lookup the enum values from the database and then create options of those enums. But if only the renders the html, then this method might not be possible. – mokuril Jun 07 '16 at 09:35
  • 2
    You'd better do that job in the model instead of the view. – BalusC Jun 07 '16 at 09:37
  • That's probably true, maybe I should just stick with the selectItems and create a bean which I pass an ID and returns SelectItem[]. Thanks for your input! – mokuril Jun 07 '16 at 11:03