tags:

views:

422

answers:

2

In many cases you want to add HTML-Controls or Facelets to your Website, but how easy is it really to just access these when you call upon an action?

I have the following commandLink to execute an Action

<h:commandLink action="#{MyBean.save}" value="">
    <f:verbatim><input type="button" value="Save"/></f:verbatim>
    <f:param name="id" value="#{MyBean.id}"/>
</h:commandLink>

The Param is there to save the QueryString-state so my application won't crash.

Now, imagine you have a <input type="text" /> or <h:inputText value="hello" /> now these components are fundamental to get your site up and running, especially if you are creating some dynamics.

However, if the Controls are not Bound to anything, or if you have a Listbox which you can add elements to with JavaScript, how do you access these when you execute the commandLink or commandButton? Do you Have to bind the controls to your Bean or is it possible to access this FaceContext in another way to retreive the values of either a listbox, input text or whatever else you would want to have?

+1  A: 

You can retrieve values from "non-JSF" controls on your page using the standard request parameter map that can be accessed with

FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap()

in whatever action you call eg. MyBean.save()

Damo
And how do you acheive the same on JSF-controls?
Filip Ekberg
you don't need to as they are bound to fields in your Beans
Damo
+1  A: 

It can be difficult to treat a JSF-rendered page as a big glob of HTML and JavaScript (which, I think, is at the heart of the question). You cannot add arbitrary form controls to the application on the client and expect the JSF framework to interpret them. JSF uses pre-defined components, so a component would have to know how to interpret the extra data coming from the request. Because it all ends up as a HTML form interpreted by a servlet, the data sent from the client will still end up in the parameter map - but, these values won't pass through the JSF lifecycle, so won't benefit from validation/data binding/etc.

A JSF control tree looks much like any other widget tree (like Swing or SWT):

UIViewRoot
         |_HtmlForm
                  |_HtmlInputText
                  |_HtmlCommandButton

A JSF control basically works like this:

  • a UIComponent instance encapsulates the values (initially populated from the JSP/Facelet); example: HtmlInputTextarea
  • When the page is rendered, the lifecycle looks up the Renderer implementation for the component; the Renderer writes markup to the output
  • When the form is posted, the same renderer looks at the incoming parameter map for keyed values it recognises and will eventually (after conversion and validation) push the new value into the UIComponent (which may in turn push it to a value binding for the model)

Taking your specific example of a listbox - this is a tricky one. JSF provides a HtmlSelectManyListbox which ends up as a SELECT element in HTML. It is possible to add OPTION children to the DOM using JavaScript on the client, but this doesn't do any good when it comes to submitting the form. If you read the HTML spec, it says:

Only selected options will be successful. When no options are selected, the control is not successful and neither the name nor any values are submitted to the server when the form is submitted.

So, when the form is submitted, only the list elements that are selected by the user would be transmitted to the server. You would need some hidden fields to get all the new data to the server. There isn't a control in the core set that will help you with this.

You have a few options:

McDowell
Amazing! I actually am using a <input type="hidden" /> at the moment which I add via javascript when i press my "save"-button. And then I retreive the posted value with FacesContext. Your answer gave me a whole new insight in the life-cycle and how to beat these problems in the future. Thank you very much.
Filip Ekberg