How can I reset JSF UIInput components to their managed bean values - java

I want to reset JSF inputs to their original managed bean values after validation failed.
I have two forms inside the same page - the first form has a commandLink to initialize the second form. The second form is rendered as a dialog whose visibility is toggled through jQuery - for the purpose of this exercise, though, I can illustrate just with two forms on the same page. Also, while I'm using PrimeFaces 2.2.x in my app, the same behaviors appear with regular h:commandLink as well.
The issue I'm having is:
click link in first form to initialize second form
submit invalid values in second form
click link in first form again to initialize second form - invalid values still there and/or UIInput state is still invalid.
For example - take the following form
<h:form id="pageForm">
<h:commandLink actionListener="#{testBean.initialize}">Initialize, no execute
<f:ajax render=":dialogForm"/>
</h:commandLink>
<br/>
<h:commandLink actionListener="#{testBean.initialize}">Initialize, execute=#this
<f:ajax execute="#this" render=":dialogForm"/>
</h:commandLink>
</h:form>
<h:form id="dialogForm">
<h:messages/>
String property - Valid: <h:outputText value="#{property.valid}"/>
<br/>
<h:inputText id="property" binding="#{property}" value="#{testBean.property}">
<f:validateLength minimum="3"/>
</h:inputText>
<br />
Int property - Valid: <h:outputText value="#{intValue.valid}"/>
<h:inputText id="intValue" binding="#{intValue}" value="#{testBean.intValue}">
<f:validateLongRange maximum="50" />
</h:inputText>
<br/>
<h:commandLink actionListener="#{testBean.submit}">
Submit
<f:ajax render="#form" execute="#form"/>
</h:commandLink>
<h:commandLink actionListener="#{testBean.initialize}">Initialize, execute=#this
<f:ajax execute="#this" render="#form"/>
</h:commandLink>
</h:form>
Bean class:
#ManagedBean
#ViewScoped
public class TestBean {
private String property = "init";
private Integer intValue = 33;
// plus getters/setters
public void submit() { ... }
public void initialize() {
intValue = 33;
property = "init";
}
}
Behavior #1
click either "Initialize" link on the pageForm
inputs get initialized to "init", "33"
now submit something invalid for both fields like "aa", "99"
now click any of the "initialize" links again (they all seem to behave the same - makes no difference whether it's in the same form or different, or whether I have specified execute="#this" or not.)
Result => UIInput.isValid() = false, both values reset though ("init", "33").
Expected => valid = true (or is this not reasonable to expect?)
Behavior #2
click either "Initialize" link on the pageForm
inputs get initialized to "init", "33"
now submit something invalid for the text field but valid for the int field ("aa", "44")
now click any of the "initialize" links again
Result => "init", valid=false; 44, valid=true
Expected => "init", valid=true; 33, valid=true
I have also looked at:
JSF 2 - Bean Validation: validation failed -> empty values are replaced with last valid values from managed bean
and
How can I populate a text field using PrimeFaces AJAX after validation errors occur?
The suggestion to explicitly reset the state of UIInputs with resetValue does work, but I'm not happy with it.
Now, I sort of understand why the isValid is not resetting - my understanding of the JSF lifecycle is that once a value is submitted to a component, isValid is not reset until the component is successfully submitted and validated and the Update Model Values phase sets the bean value. So there may be no way around explicitly resetting the valid state in this case, since I want to use #{foo.valid} for conditional CSS styling.
What I don't understand, though, is why the components that successfully validated are not re-initializing from the bean. Perhaps my understanding of the JSF lifecycle is slightly off?
I understand the rules layed out in the answer to How can I populate a text field using PrimeFaces AJAX after validation errors occur? as they pertain to an individual component but not to the form as a whole - i.e., what happens if a component succeeds validation but the validation overall fails?

In fact, there may turn out to be no better way than explicitly calling resetValue on components. In my case, all of the dialogs are in the same big JSF view tree with the underlying page that opens them. So from JSF's perspective, the same view component state including invalid input values should be preserved until we navigate away from the view, as it has no visibility into how we're toggling display attributes client-side.
The only other thing that might work is if the components that make up the dialog are actually not rendered in the JSF view tree unless they're visible. In my case, they're always rendered, using CSS to toggle visibility.

Related

Boolean value in backing bean not updated with ajax call

I'm trying to set the value in the backing bean based on the checkbox selection.
Here is the Checkbox:
...
<f:view>
<p:panel header="HEADER">
<p:selectBooleanCheckbox id="TEST_CB" itemLabel="TEST CB"
value="#{myBB.test}">
<p:ajax execute="#this" update="someComponent"/>
</p:selectBooleanCheckbox>
...
In the backing bean, I have a boolean property test with public getter and setter.
When I click on the checkbox, the setter in the backing bean is called(so far so good), but the value which is passed as a parameter is always false.
I've been messing with it for two hours, trying different combinations of p:ajax parameters, immediate and partial on the p:selectBooleanCheckbox, I've also tried using h:selectBooleanCheckbox, but it is still false.
I use Apache MyFaced 2.1.10 and Primefaces 3.5
The button was not in the form.
After adding <h:form> tag, everything is ok.

Why is this invalid EL expression?

I'm doing a simple logout and want to make sure i'm referencing correctly to the login root.
<h:form>
<h:commandLink value="Logout" action="#{request.contextPath}/#{userController.logout()}" />
</h:form>
but i get this error:
/topnav.xhtml #16,104 action="#{request.contextPath}/#{userController.logout()}" Not a Valid Method Expression: #{request.contextPath}/#{userController.logout()}
UPDATE
Right now I'm adding navigation rules from the logout link to the login page and since the logout link is on all pages i need to add rules to allow the transition back to the login page. that seems like a lot of configuration for a simple item. would prefer to just have the method called indicate that the login page the the final destination and hot have to place a navigation entry from all pages to the login page.
From the documentation for commandLink:
Name Required Request-time Type
==============================================================
action false false javax.el.MethodExpression
The composite expression #{request.contextPath}/#{userController.logout()} cannot be resolved as a MethodExpression.
The JSF 2.1 specification says of MethodExpressions:
Method expressions are a very similar to value expressions, but rather
than supporting the dynamic retrieval and setting of properties,
method expressions support the invocation (i.e. execution) of an
arbitrary public method of an arbitrary object, passing a specified
set of parameters, and returning the result from the called method (if
any).
try
<h:form>
<h:commandLink value="Logout" action="#{userController.logout()}" />
</h:form>
beside the fact that you do not need context, you can not use # twice the way you are using it.

Conditionally rendered button, design, calling an action

JFS1.2 + Richfaces 3.3
Situation is as follows:
JSP page renders conditionally one or another panelGroup.
Within each panelGroup there are couple setters and one command button.
Each of two panelGroups uses own bean for setting and performing action.
On the top of a page there's selectOneRadio with (obvious) two items - coresponding tow options of conditional rendering.
Page renders properly, switcher causes to render appropriate panel.
Case is, commands buttons doesn't call an action.
I know what's going on - when I click a button to call action dom is regenerated, but the value that hold my decision to display particular panel doesn't exist anymore. The button is not recreated, action is not fired.
Technically:
<h:selectOneRadio value="#{reportType}">
<f:selectItem itemLabel="x" itemValue="x"/>
<f:selectItem itemLabel="y" itemValue="y"/>
<a4j:support event="onclick" reRender="xPanel, yPanel/>
</h:selectOneRadio>
<h:panelGrid id="xPanel "columns="2" rendered="#{reportType eq 'x'}">
<...some setters>
<... commandbutton>
</h:panelGrid>
<h:panelGrid id="yPanel "columns="2" rendered="#{reportType eq 'y'}">
<...some setters>
<... commandbutton>
</h:panelGrid>
Question is, how to design the page to obtain proper rendering and actions?
For now, I created additional session bean that holds switching value (x|y), but that desing smells bad for me...
RichFaces 3.3 offers the <a4j:keepAlive> tag which does basically the same as Tomahawk's <t:saveState> and JSF2 #ViewScoped. Add the following line somewhere in your view:
<a4j:keepAlive beanName="#{bean}" />
This will keep the bean alive as long as you're returning null or void from action(listener) methods.
See also:
JSF 1.2: How to keep request scoped managed bean alive across postbacks on same view?

h:commandLink not working when inside a list

I have a problem with RichFaces and creating lists of links. If you attempt to use any type of commandLink inside a list (I've tried ui:repeat and rich:list) the action on that link is not called. I've also tried commandButton and the a4j variations of those. I'm using JSF 2, RichFaces 4 on Jboss 6.
<rich:list var="venue" value="#{searchManager.results}" type="definitions" stateVar="status">
<h:form>
<h:commandLink value="CLICK IT" immediate="true" action="#{score.selectVenue}" />
</h:form>
</rich:list>
The position of the form also doesn't matter.
<h:form>
<rich:list var="venue" value="#{searchManager.results}" type="definitions" stateVar="status">
<h:commandLink value="CLICK IT" immediate="true" action="#{score.selectVenue}" />
</rich:list>
</h:form>
If I just have the link by itself (no list) it works.
Any help would be greatly appreciated.
When you click a command link or press a command button to submit a form, JSF will during the apply request values phase scan the component tree for the command link/button in question so that it can find the action expression associated with it, which is in your case #{score.selectVenue}.
However to be able to ever reach that, you would need to ensure that #{searchManager.results} returns exactly the same list as it did when the form was displayed. Because with an empty result list, there would be no command link/button in the view at all during the apply request values phase of the form submit.
Your #{searchManager} bean seems to be request scoped. Request scoped beans have a lifetime of exactly one request-response cycle. So when you submit the form, you'll get a brand new and another instance of the request scoped bean than it was when the form was displayed. The results property seems not to be preserved during (post)construction of the bean and thus remains empty. So JSF cannot find the command link/button in question and thus cannot find the action expression associated with it and thus cannot invoke it.
As you're using JSF2, an easy fix is to place the bean in the view scope. This way the bean will live as long as you're submitting and navigating to exactly the same view by returning null or void in action methods.
#ManagedBean
#ViewScoped
public class SearchManager {
// ...
}
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated

Determine the ID of the JSF container form

I need to determine the ID of a form field from within an action handler. The field is a part of a included facelets component and so the form will vary.
included.xhtml
<ui:component>
<h:inputText id="contained_field"/>
<h:commandButton actionListener="#{backingBean.update}" value="Submit"/>
</ui:component>
example_containing.xhtml
<h:form id="containing_form">
<ui:include src="/included.xhtml"/>
</h:form>
How may I determine the ID of the form in the update method at runtime? Or better yet, the ID of the input field directly.
Bind the button to your backing bean, then use getParent() until you find the nearest form.
Programmatically I would use jsight's method. You can know the id of your elements (unless you let JSF create them, I don't know the means for numbering in the ids) by looking at it. h:form is a naming container so as long as you don't have it wrapped in another naming container it will be containingForm:containedfield The ':' is the naming separator by default is JSF and the ids are created like this, roughly anyway, (parentNamingContainerId:)*componentId
Since update method is of type actionListener, you can access your UI component as follows
public void update(javax.faces.event.ActionEvent ac) {
javax.faces.component.UIComponent myCommand = ac.getComponent( );
String id = myCommand.getId(); // get the id of the firing component
..... your code .........
}

Categories