So I had this problem with a JSF Custom Component for which it took me 3 days to find the answer.
The problem: Inside a custom component, modify the value of a bound piece of data in a hidden input.
Ok, so in a normal JSF page you'd simply place the tag in page and bind it to data on your bean. It'd look something like this:
<h:inputHidden value="#{myBean.data}"/>
Using that on your page, you could modify the value with javascript and it would save back to your bean just fine. But putting it in a custom component made things weird.
There are other articles on how to create a whole JSF Custom component. I'm not going to repeat them here because they all show you the basics quite well. I will recommend anything you see from the author BalusC. Moving on.
In this example, I'll create an entirely unnecessary tag <myCompany:hidden>. It will simply render a hidden input on the page using the HtmlInputHidden object.
A quick reminder, I'm only going to address the rendering portion of this tag.
When you create your component rendering class, whether it's a separate one or not, there are a few JSF methods that you will use to get everything on the page. These are encodeBegin, encodeChildren, & encodeEnd.
encodeBegin renders what should appear in your page where the opening tag is. encodeChildren handles what is rendered between the opening and closing tags. Finally, encodeEnd renders what should appear with the closing tag.
A more concrete example of that:
JSF Code | When it gets rendered | |
<h:panelGrid columns="2" styleClass="prettyStyle"> | encodeBegin | |
<h:outputText value="Hello"> | encodeChildren | |
<h:outputText value="World!"> | encodeChildren | |
</h:panelGrid> | encodeEnd |
Here's where things get weird. For our tag, all we really want to do is have it render a single hidden input, right at the start and be done with it. But that won't work. Sure, you can get the value set on the page, but it won't be bound to your bean. Instead, create the HtmlInputHidden object, bind its value, and add it as a child to your component by calling: this.getChildren().add(myHtmlInputHidden);.
This will be encoded during the encodeChildren call and be properly bound, assuming you've done everything else right.
As with all JSF Custom Component creation, it's a little obtuse until you try it. Then it's still obtuse, and hard, but it works.