Let's say I have five or more input computers that can affect whether a single drop down menu is displayed. The issue I am running into is that if the drop down menu is displayed once (thus setting the value in the backing bean through ajax) and the user then changes one of the affecting input components, then the backing bean value of the drop down menu is not getting reset when the drop down goes into hiding using the rendered property. For example:
<h:selectOneMenu id="sampleDropDown" required="false" immediate="true"
onchange="jsUpdateSampleDropDownValue()" value="#{backingBean.value}"
rendered="#{backingBean.shouldShowSampleDropDown}"
actionListener="#{backingBean.listener}" />
I understand that I have options here. I've debated whether I should add a generic ValueChangeListener (apply request values phase) or an EventHandler (render response phase) that would listen in on the values of the other inputs and make a decision on whether to clear the drop down menu value but this certainly is more work then just letting the rendered property make that decision.
We've seen dozens of the same type of issue on the project I'm currently on and I'd really like to hear from the experts on the best practice for handling this type of situation. In case it matters we are using custom ajax (not ajax4jsf) and jsf 1.1. Any help is appreciated.
The solution I came up with is to not try and reset the input component in the backing bean value of the renderered property.
I have a phase listener attached to the single page interface and am essentially passing request parameters in the javascript method (i.e. jsUpdateSampleDropDownValue()) so that business logic data can be loaded in the rendered response phase using the chain of responsibility pattern.
When a request parameter is passed (i.e. RESET_SAMPLE_DROP_DOWN) onchange that matches a corresponding event handler (i.e. ResetSampleDropDownEventHandler), I check a separate "constraint" class (see Hardcore Java book) that validates whether enough data is accumulated before either clearing the binding value or continuing with the request.
This allows the logic to be centralized yet be attached to multiple components. You may be asking why a single JSF ValueChangeListener was not attached to each component which would allow the same re-use. The reason for this is because our business logic takes place in the render response phase after the update model phase so it makes sence that any "reset" type methods occur after any "defaulting" of values.
Related
There are lot of materials out there differentiating value attribute and binding attribute in JSF.
I'm interested in how both approaches differ from each other. Given:
public class User {
private String name;
private UICommand link;
// Getters and setters omitted.
}
<h:form>
<h:commandLink binding="#{user.link}" value="#{user.name}" />
</h:form>
It is pretty straight forward what happens when a value attribute is specified. The getter runs to return the name property value of the User bean. The value is printed to HTML output.
But I couldn't understand how binding works. How does the generated HTML maintain a binding with the link property of the User bean?
Below is the relevant part of the generated output after manual beautification and commenting (note that the id j_id_jsp_1847466274_1 was auto-generated and that there are two hidden input widgets).
I'm using Sun's JSF RI, version 1.2.
<form action="/TestJSF/main.jsf" enctype="application/x-www-form-urlencoded"
id="j_id_jsp_1847466274_1" method="post" name="j_id_jsp_1847466274_1">
<input name="j_id_jsp_1847466274_1" type="hidden" value="j_id_jsp_1847466274_1">
Name
<input autocomplete="off" id="javax.faces.ViewState" name="javax.faces.ViewState"
type="hidden" value="-908991273579182886:-7278326187282654551">
</form>
Where is the binding stored here?
How does it work?
When a JSF view (Facelets/JSP file) get built/restored, a JSF component tree will be produced. At that moment, the view build time, all binding attributes are evaluated (along with id attribtues and taghandlers like JSTL). When the JSF component needs to be created before being added to the component tree, JSF will check if the binding attribute returns a precreated component (i.e. non-null) and if so, then use it. If it's not precreated, then JSF will autocreate the component "the usual way" and invoke the setter behind binding attribute with the autocreated component instance as argument.
In effects, it binds a reference of the component instance in the component tree to a scoped variable. This information is in no way visible in the generated HTML representation of the component itself. This information is in no means relevant to the generated HTML output anyway. When the form is submitted and the view is restored, the JSF component tree is just rebuilt from scratch and all binding attributes will just be re-evaluated like described in above paragraph. After the component tree is recreated, JSF will restore the JSF view state into the component tree.
Component instances are request scoped!
Important to know and understand is that the concrete component instances are effectively request scoped. They're newly created on every request and their properties are filled with values from JSF view state during restore view phase. So, if you bind the component to a property of a backing bean, then the backing bean should absolutely not be in a broader scope than the request scope. See also JSF 2.0 specitication chapter 3.1.5:
3.1.5 Component Bindings
...
Component bindings are often used in conjunction with JavaBeans that are dynamically instantiated via the Managed
Bean Creation facility (see Section 5.8.1 “VariableResolver and the Default VariableResolver”). It is strongly
recommend that application developers place managed beans that are pointed at by component binding expressions in
“request” scope. This is because placing it in session or application scope would require thread-safety, since
UIComponent instances depends on running inside of a single thread. There are also potentially negative impacts on
memory management when placing a component binding in “session” scope.
Otherwise, component instances are shared among multiple requests, possibly resulting in "duplicate component ID" errors and "weird" behaviors because validators, converters and listeners declared in the view are re-attached to the existing component instance from previous request(s). The symptoms are clear: they are executed multiple times, one time more with each request within the same scope as the component is been bound to.
And, under heavy load (i.e. when multiple different HTTP requests (threads) access and manipulate the very same component instance at the same time), you may face sooner or later an application crash with e.g. Stuck thread at UIComponent.popComponentFromEL, or Threads stuck at 100% CPU utilization in HashMap during JSF saveState(), or even some "strange" IndexOutOfBoundsException or ConcurrentModificationException coming straight from JSF implementation source code while JSF is busy saving or restoring the view state (i.e. the stack trace indicates saveState() or restoreState() methods and like).
Also, as a single component basically references the rest of the entire component tree via getParent() and getChildren(), when binding a single component to a view or session scoped bean, you're essentially saving the entire JSF component tree in the HTTP session for nothing. This will get really costly in terms of available server memory when you have relatively a lot of components in the view.
Using binding on a bean property is bad practice
Regardless, using binding this way, binding a whole component instance to a bean property, even on a request scoped bean, is in JSF 2.x a rather rare use case and generally not the best practice. It indicates a design smell. You normally declare components in the view side and bind their runtime attributes like value, and perhaps others like styleClass, disabled, rendered, etc, to normal bean properties. Then, you just manipulate exactly that bean property you want instead of grabbing the whole component and calling the setter method associated with the attribute.
In cases when a component needs to be "dynamically built" based on a static model, better is to use view build time tags like JSTL, if necessary in a tag file, instead of createComponent(), new SomeComponent(), getChildren().add() and what not. See also How to refactor snippet of old JSP to some JSF equivalent?
Or, if a component needs to be "dynamically rendered" based on a dynamic model, then just use an iterator component (<ui:repeat>, <h:dataTable>, etc). See also How to dynamically add JSF components.
Composite components is a completely different story. It's completely legit to bind components inside a <cc:implementation> to the backing component (i.e. the component identified by <cc:interface componentType>. See also a.o. Split java.util.Date over two h:inputText fields representing hour and minute with f:convertDateTime and How to implement a dynamic list with a JSF 2.0 Composite Component?
Only use binding in local scope
However, sometimes you'd like to know about the state of a different component from inside a particular component, more than often in use cases related to action/value dependent validation. For that, the binding attribute can be used, but not in combination with a bean property. You can just specify an in the local EL scope unique variable name in the binding attribute like so binding="#{foo}" and the component is during render response elsewhere in the same view directly as UIComponent reference available by #{foo}. Here are several related questions where such a solution is been used in the answer:
Validate input as required only if certain command button is pressed
How to render a component only if another component is not rendered?
JSF 2 dataTable row index without dataModel
Primefaces dependent selectOneMenu and required="true"
Validate a group of fields as required when at least one of them is filled
How to change css class for the inputfield and label when validation fails?
Getting JSF-defined component with Javascript
Use an EL expression to pass a component ID to a composite component in JSF
(and that's only from the last month...)
See also:
How to use component binding in JSF right ? (request-scoped component in session scoped bean)
View scope: java.io.NotSerializableException: javax.faces.component.html.HtmlInputText
Binding attribute causes duplicate component ID found in the view
each JSF component renders itself out to HTML and has complete control over what HTML it produces. There are many tricks that can be used by JSF, and exactly which of those tricks will be used depends on the JSF implementation you are using.
Ensure that every from input has a totaly unique name, so that when the form gets submitted back to to component tree that rendered it, it is easy to tell where each component can read its value form.
The JSF component can generate javascript that submitts back to the serer, the generated javascript knows where each component is bound too, because it was generated by the component.
For things like hlink you can include binding information in the url as query params or as part of the url itself or as matrx parameters. for examples.
http:..../somelink?componentId=123 would allow jsf to look in the component tree to see that link 123 was clicked. or it could e htp:..../jsf;LinkId=123
The easiest way to answer this question is to create a JSF page with only one link, then examine the html output it produces. That way you will know exactly how this happens using the version of JSF that you are using.
I could do with some help once again...
We built our own forms in XPages. Forms are defined by a user in Notes, and they are used through XPages/web. We added several managed beans to get more grip on the data used by the page and controls that are on it. The whole thing is heavily nested, the form control can be used more than once on a page, repeat controls are used as well, and now I need to partially refresh a panel.
Some of the code:
<xp:panel id="ccAnyForm">
<xp:this.dataContexts>
<xp:dataContext var="formulaire">
<xp:this.value><![CDATA[#{javascript:compositeData.formName || compositeData.dataSource.getItemValueString("Formulaire")}]]></xp:this.value>
</xp:dataContext>
<xp:dataContext var="formdata">
<xp:this.value><![CDATA[#{javascript:PageData.getForm(formulaire, compositeData.dataSource)}]]></xp:this.value>
</xp:dataContext>
</xp:this.dataContexts>
<xp:panel id="aFormulaire${javascript:compositeData.name}">
<xe:switchFacet id="switchFacet1">
<xe:this.selectedFacet><![CDATA[#{javascript:formdata.isTabbed()? "tabbed": "flat"}]]></xe:this.selectedFacet>
PageData is a Java bean, and I lose formdata when doing a partial refresh. If I set partial execution mode in the EventHandler (data validation is disabled), I get the error that says formdata not found on the last line of the snippet. If I clear partial execution mode, I get nothing at all: no error, no Java error, no SSJS error, nothing.
It must be my lack of understanding the life-cycle of objects and variables, for I prbably have to use ValueBindings or so, but I don't know how.
Help...
I've seen dataContexts recalculate as null, particularly when dependent on other dataContexts. I think in Apply Request Values phase. When I had that I changed the code to only calculate in Render Response phase.
However, I don't think that work for you, because the Switch control will need the value before Render Response, and there's no easy way to get hold of which other phase is running.
The approach I'd take is to have a property in your bean (e.g. showTabbed) that holds which Switch facet to show. Call a bean method to set that property on page load. Then in your partial refresh, call the method again, checking whether the Formulaire field has changed to determine whether or not to call setShowTabbed(boolean) again. That will minimise the number of calls even more and should prevent the problem.
I have a struts action flow(struts-1.x framework), which, when executes, the action class ActionFlowActionUnit1.java sets a String variable varName to request using the code
request.setAttribute("varNameFromRequest", varName);
and the flow finally leads to the loading of a jsp Page1.jsp.
Now, Page1.jsp contains a button, which, when clicked, initiates a new struts action flow, which has the action class ActionFlowActionUnit2.java. In this class, I want to use the varName which I had set in request using request.getAttribute().
How can I do it WITHOUT USING SESSION?
Technically, I'm not sure if achieving this using requestis possible, because, triggering a new struts-action will lose all other information in the request that was previously set (if I'm correct).
I couldn't get anything from Google.
As you say, it is not feasible technically as you want it (every http request from the browser creates a new HttpServletRequest object)
You have 2 options:
Using the Session, which you want to avoid as far as I understand
Bring back and forth some parameter into every successive request with the value you would like to keep.
The second option would mean to store some parameter inside your Page1.jsp <form> with the variable you need your second action to receive, and then rinse and repeat. This is a pure html form solution.
If you are implementing a complex flow, this looks a fair case to have a look at Spring Webflow. There you can manage flow-level variables, which are stored at a "different" scope than request or session, and looks exactly what you want.
http://projects.spring.io/spring-webflow/
My user requires any validation items (e.g. piece of data missing) to be displayed on screen, and not to be actually enforced (i.e. not to be checked to be totally valid) until further along in the process.
To accomplish this, on every save, I'll be checking for the presence of certain data. On initial object creation (of the object to be validated), I'm going to create a list of Validation items referring to specific fields (or their getters) as necessary. I will then be able to run through these items on each and every save, to check whether each item is "Valid" or not. At any point, I'll be able to display validation results to the user, as required.
Does this sound like a sensible approach? Am I missing a standardised way of approaching this task?
Usually validation is not done on save but on change. That simply means you have to attach change listeners to your fields, which then all execute your validation routine.
Listeners are only attached to the fields that are part of
validation.
Validation routine usually builds a list of errors/warnings which can be later presented in your UI
Also using JGoodies Validation will simplify your task. It is the best validation framework for Swing IMO
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()