Using commandButton or commandLink to for Postback and managing the HTML Control Values
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?
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:
- Find an existing control from a 3rd party library that does this. If you can't find one, consider using AJAX to perform the updates - look at the RichFaces select controls for inspiration.
- Write your own control (warning: read the spec and be aware of the many fiddly, manual steps)
- Put up with having to perform a POST operation every time you want to add an element to the list
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()
精彩评论