Value remains in form field after it is cleared in bean in JSF2 - validation

In my JSF2 application, I have "Clear" button, which is supposed to clear all the fields. However, it doesn't always work.
My page fragment:
<h:form id="bi">
<h:inputText value="#{bean.entity.firstname}" />
<h:inputText value="#{bean.entity.surname}" />
<h:commandButton value="Clear" immediate="true" action="#{bean.clear}">
<f:ajax render="bi" />
</h:commandButton>
<h:commandButton value="Submit" action="#{bean.submit}" />
</h:form>
And clear() method in my bean:
public void clear() {
entity = new Entity();
}
If I enter values in the fields, and click "Clear", everything is cleared as expected. However, consider such scenario:
1. Enter value only in one field (both are required by JSR303 annotations on entity).
2. Click "Submit". Error message appears.
3. Click "Clear".
Entered value remains. Why is it not cleared?
Moreover, if I clear it by hand, and click "Clear", it returns to the field. I checked that it comes to the browser in partial response after clicking "Clear" button. I suspect it has something to do with view state.
Moreover, if I add validator="#{bean.validate}" to the field, it enter this validation. Even if button has immediate="true" attribute. Why? Shouldn't immediate button ommit validation?

You've run into a more or less well-known issue regarding updating components for which validation has already happened.
This post is rather old, but still relevant: http://ishabalov.blogspot.com/2007/08/sad-story-about-uiinput.html
There is a community created solution for A4J in JSF 1.2 posted here: http://community.jboss.org/thread/8446?start=15&tstart=0
But unfortunately, this doesn't work directly in JSF 2.0 and in your case it wouldn't work at all since it's A4J specific. Nevertheless it might be a source of inspiration.
Basically you need to walk the component tree and clear its state. The neatest thing is to clear exactly the state of the components that you are going to re-render. But you might take the brute-force approach and just clear all if your particular application or page can tolerate that.

I wound up having to avoid submit or action to get the form to clear properly. I used actionListener with a void bean method instead.
But then I faced the problem of conditionally needing navigation which is usually done with a String method from action. I used ExternalContext.redirect() to accomplish that which I learned from the following:
JSF PostConstruct Exception Handling - Redirect
JSF navigation redirect to previous page
my page code:
<p:commandButton value="Login" update=":loginForm"
actionListener="#{loginBean.login}"/>
my bean code:
public void login() {
RtsLDAPAD laLdap = new RtsLDAPAD();
boolean lbAuthenticated = false;
try
{
lbAuthenticated = laLdap.login(userName, password);
System.out.println(
"The Result is " + lbAuthenticated + " for " + userName);
}
catch (Exception aeRTSEx)
{
aeRTSEx.printStackTrace();
}
if (lbAuthenticated) {
try {
FacesContext.getCurrentInstance().getExternalContext().redirect("taskform.jsf");
} catch (IOException e) {
e.printStackTrace();
}
} else {
FacesContext facesContext = FacesContext.getCurrentInstance();
facesContext.addMessage(null,
new FacesMessage("Login failed for " + userName + "."));
UIViewRoot uiViewRoot = facesContext.getViewRoot();
HtmlInputText inputText = null;
Password pwd = null;
inputText = (HtmlInputText) uiViewRoot.findComponent("loginForm:username");
inputText.setSubmittedValue(null);
inputText.setValue(null);
inputText.setLocalValueSet(false);
inputText.setValid(true);
pwd = (Password) uiViewRoot.findComponent("loginForm:password");
pwd.setSubmittedValue(null);
pwd.setValue(null);
pwd.setLocalValueSet(false);
pwd.setValid(true);
userName = null;
password = null;
}
}

Related

Primefaces p:cache

I'm having some problem with Primefaces p:cache component
This is example how its used on testpage/index.xhtml
<h:form>
<p:panel header="Testsite">
<p:cache region="testsite2"
key="testsite2#{user.id}#{user.defaultLanguage}">
<p:commandButton action="#{testBean.hello}" value="btn"
rendered="#{testBean.renderedButton}">
</p:commandButton>
</p:cache>
</p:panel>
</h:form>
and this is back end bean
#ManagedBean(name = "testBean")
#ViewScoped
public class TestBean {
#PostConstruct
public void init() {
System.out.println("init");
}
public void hello() {
System.out.println("hello");
}
public boolean isRenderedButton() {
System.out.println("isRenderedButton");
return true;
}
}
So on first page hit init and isRenderedButton message are printed normally as expected. After that when I click on button I do expect to see hello message printed, but that's not case here. Can anyone point me in right direction ?
According to Primefaces showcase for p:cache with buttons I was expecting this behavior.
Right now I am using Primefaces.DEFAULT_CHACHE_PROVIDER and later I will switch to ehcache.
I'm using PF 5.3, sun faces 2.2.12.
Thanks.
To answer myself (and maybe ill help someone), i was trying to create dynamic menu from database and i wanted to cache generated content with p:cache component. But back then every menu item would call bean method which would redirect user to page and that was problem in first place.
So i had something like this:
<p:menu>
<p:submenu label="Human resource">
<p:menuitem value="Search person" actionListener="#{bean.navigateUserToSearchPerson}"/>
</p:submenu>
I actually did not fix this problem (had no extra time to investigate problem), so i came up with idea to generate links for each menu item, so when user clicks on menu item, it would redirect him to new page. So now i don't have any AJAX calls in menu and caching works fine now.
Code example:
<p:cache region="appUiCache" key="panelMenu#{user.id}#{user.defaultLanguage}">
<p:panelMenu id="sm" model="#{bean.menuModel}" stateful="true" />
</p:cache>
Menu items are created dynamically from database:
DefaultMenuItem defaultMenuItem = new DefaultMenuItem(...);
defaultMenuItem.setIcon(item.getIcon());
defaultMenuItem.setUrl(item.getUrl()); <!-- This is new url part -->
This works fine now in production. Thanks.

Ajax for valueChangeListener

I'm using the p:ajax listener to handle value change events (because valueChangeListener is launched on form submit):
<p:ajax event="change" listener="#{bean.onNameChanged}"/>
Handle method:
public void onNameChanged(final AjaxBehaviorEvent event)
The problem is, I can't find in AjaxBehaviorEvent nor its class hierarchy the place to read the old value of the input. Neither could I find hint in google, how to get the old value...
How to access the old value in the p:ajax onChange event?
The problem is, I can't find in AjaxBehaviorEvent nor its class hierarchy the place to read the old value of the input. Neither could I find hint in google, how to get the old value...
Use a valueChangeListener.
Unfortunatelly, valueChangeListener is invoked before p:ajax, so I don't have actual data from forms in that method, so in theory I could use valueChangeListener to remember the old value and then wait for p:ajax to process...
Queue the value change event to the invoke application phase.
public void valueChangeListenerMethod(ValueChangeEvent event) {
if (event.getPhaseId() != PhaseId.INVOKE_APPLICATION) {
event.setPhaseId(PhaseId.INVOKE_APPLICATION);
event.queue();
return;
}
// Do your original job here.
// It will only be invoked when current phase ID is INVOKE_APPLICATION.
}
The ValueChangeListener should work this way:
The view:
<h:form>
<h:inputText value="#{sessionBean.hello}"
valueChangeListener="#{sessionBean.valueChangeListener}">
<p:ajax/>
</h:inputText>
</h:form>
The bean:
public void valueChangeListener(ValueChangeEvent e) {
System.out.println("valueChangeListener invoked:"
+ " OLD: " + e.getOldValue()
+ " NEW: " + e.getNewValue());
}
The above code will print if I change the text field from "hello" to "world":
valueChangeListener invoked: OLD: hello NEW: world
You could try the following:
Implement the value change event in your bean
public void processValueChange(ValueChangeEvent e){
//foo the bar
}
Define a valueChangeListener on your selection component
<p:selectOneMenu value="#{yourBean.value}" onchange="submit()" valueChangeListener="{#yourBean.processValueChange}">
The key piece there is the submit() bit that processes the enclosing form on change of the value. You can then getNewValue() and getOldValue() as necessary.
EDIT: Now that I think about it, I see no reason why you cannot leave your setup as-is and simply define the valueChangeListener. It should still be processed during the change event in the <p:ajax/>, in fact, it will be processed before the listener for the ajax event itself.
you can use this:
public void onNameChanged(AjaxBehaviorEvent event)
{
String myVal = (String) ((UIOutput) event.getSource()).getValue();
System.out.println("myVal: " + myVal);
}
Workaround is possible (tested with Primefaces 10):
<p:inputText id="name" value="bean.name">
<p:ajax event="valueChange" update="name"
listener="#{bean.onNameChanged}"
onstart="cfg.ext={params:[{name:'oldValue', value:'#{bean.name}'}]};"/>
</p:inputText>
update="name" is important, to get each time the new value into the javascript event handler.
Bean Method:
public void onNameChanged(final AjaxBehaviorEvent event) {
String oldValue = getFacesContext().getExternalContext().getRequestParameterMap()
.get("oldValue");
//Do with oldValue, whatever you want
}

Validation with JSF 2 only wanted on submit

I have an issue with validation, as I only want validation to take place when the submit button is clicked on the screen, not when another button is clicked.
In the displayed page option1.faces is the main file option1.xhtml, and several included files. Below are fragments of code from the main page and two of the included files:
Code in option1.xhtml:
<h:inputText size="4" maxlen="5" id="teff1" value="#{option1.teff1}">
<f:validateDoubleRange minimum="#{option1.teff1Min}" maximum="#{option1.teff1Max}"
disabled="#{simulator.validate}"/>
</h:inputText>
Code in abundances0.xhtml that is included in option1.xhtml:
<h:selectOneMenu id="abundanceSet0" value="#{abundance.abunSet0}" style="height:25px; width:180px;">
<f:selectItems value="#{abundance.abunSetMap}"/>
</h:selectOneMenu>
<p:spacer width="37" height="0"/>
<p:commandButton value="Select Set" actionListener="#{abundance.selectSet0}" update="abundances0"/>
Code in footerButtons.xhtml that is included in option1.xhtml:
<h:message for="teff1" style="color:red"/>
<h:commandButton value="Submit" disabled="#{!login.loggedIn}" action="#{simulator.submit}" onclick="resetForm()"
actionListener="#{simulator.validate}" class="button"/>
The fragments of code from the corresponding beans are here:
MyOption1Bean:
#ManagedBean(name="option1")
#SessionScoped
public class MyOption1Bean implements Serializable {
// Lots of other private variables and objects
private String teff1;
private String teff1Min;
private String teff1Max;
// Option 1 constructor to initialze limits
public MyOption1Bean() {
ResourceBundle bundle = ResourceBundle.getBundle("com.csharp.validation");
teff1Min = bundle.getString("teff1Min");
teff1Max = bundle.getString("teff1Max");
}
public String getTeff1() {
return teff1;
}
public void setTeff1(String teff1) {
this.teff1 = teff1;
}
// Lots of getters, setters, methods, etc.
}
MyAbundanceBean:
#ManagedBean(name="abundance")
#SessionScoped
public class MyAbundanceBean implements Serializable {
// Lots of other private variables and objects
public String getAbunSet0() {
return abunSet[0];
}
public void setAbunSet0(String abunSet) {
this.abunSet[0] = abunSet;
}
public Map<String,String> getAbunSetMap() {
return abunSetMap;
}
public void selectSet0(ActionEvent e) {
selectSet(0);
}
// Lots of getters, setters, methods, etc.
}
MySimulatorBean:
#ManagedBean(name="simulator")
#SessionScoped
public class MySimulatorBean implements Serializable {
// Lots of other private variables and objects
private boolean validate;
// When validate is true disabled is false so validation takes place.
public boolean isValidate() {
return !validate;
}
// When navigating away from the home page to one of the options, reset the error
// and validate flags.
public void resetError(ActionEvent event) {
error = false;
validate = false;
}
// On clicking "Submit" this enables the validate flag.
public void validate(ActionEvent event) {
validate = true;
}
// On clicking "Submit" this gets the user's input, and if succesful sends it to an output file then
// navigate to a "Success" page, otherwise return to the original page.
public String submit() {
// Code to check for errors and output data to a file.
}
// Lots of getters, setters, methods, etc.
}
In option1 (the xhtml and the bean files) the user enters a value for teff1, which must be between teff1Min and teff1Max, which are obtained from a properties file. This works correctly, and if a value for teff1 is not given or is out of range, on clicking the "Submit" button, as given in the footerButtons.xhtml, the submit fails and and the <h:message/> tag displays an error.
However, before clicking "Submit", if the input field for teff1 is empty or has a wrong value,
the <p:commandButton value="Select Set" .../> in the included abundances0.xhtml does not work. It is supposed to update a display with a chosen menu, which otherwise it does. I set the immediate
attribute of <p:commandButton value="Select Set" /> to true, but it still does not work. I only want the validation to take place when the "Submit" button is clicked, and nothing else.
I tried an alternative way: where the flag validate in the simulator bean is used to disable the validation until it is wanted. Namely, when the option1 page is visited it is false, to disabled is true, and no validation is done until the submit button is clicked, at which point it is set to true, so disabled is false. Unfortunately, this dose not work, as JSF thinks the page is valid and navigates away from it before validation is performed. This is in spite of the fact that validate() is executed before submit() in the simulator bean. This is confirmed by inserting a print statement in each of them.
Does anybody have any idea as to what is going on?, and is there an easy way of making sure that validation only takes place when the submit button is clicked? Otherwise the display is locked up, and I'm unable to make the other buttons work.
Many thanks for the clarification, and I did exactly what you suggested. I did the following:
First I put immdiate="true" in the command button that selects a menu in my abundances0.xhtml file:
<p:commandButton value="Select Set" actionListener="#{abundance.selectSet0}" update="abundances0" immediate="true"/>
then I changed the action in my abundance bean java file:
public void selectSet0(ActionEvent e) {
selectSet(0);
FacesContext.getCurrentInstance().renderResponse();
}
but it still does not work. If I click the button nothing happens unless a valid value is already in the input field for teff1 in the option1.xhtml file at the beginning. I need this button to work, together with other ones like it, regardless of what is in the input field, until the submit button is clicked. As far as I can see, I am doing everything correctly.
Icidentally, I'm using JSF 2.0 with PrimeFaces 3.4.2 and Eclipse Indigo.
The <p:commandButton> processes by default the entire form, as in process="#form".
You need to tell it to process only itself, as in process="#this".
<p:commandButton ... process="#this" />
This way all input components in the same form won't be processed (converted/validated/updated).
First of all, validation in JSF is performed in one of the Faces lifecycle, to be more specific, it's done at PROCESS_VALIDATIONS phase. The only way to skip validation is to instruct the Faces' lifecycle to skip that phase.
In JSF input & command components have an immediate attribute, which means that those with a true value for it will be processed during the APPLY_REQUEST_VALUES phase, instead of going through the whole Faces' lifecycle.
Behaviour is slightly different depending of the type of component:
input components with immediate="true" will be validated at APPLY_REQUEST_VALUES phase instead of the PROCESS_VALIDATION one.
command components with immediate="true" will be executed at APPLY_REQUEST_VALUES phase instead of the INVOKE_APPLICATION one.
So, to skip validation, a possible approach would be to have a <h:commandButton /> with immediate="true" and then, at the backing bean side invoke either FacesContext.getCurrentInstance().renderResponse() or FacesContext.getCurrentInstance().requestComplete() to tell Faces to skip the remaining lifecycle phases.
So, in your select0 method should be:
public void selectSet0(ActionEvent e) {
selectSet(0);
FacesContext.getCurrentInstance().renderResponse(); // skip the remaining phases and go straight to RENDER_RESPONSE
}
NOTE: Bear in mind that when submitting a form with an immediate command will trigger the validation in all of the immediate inputs of that form.

strange jsf panelgroup binding -> h:selectOneMenu validation Exception

lets start simple:
- an easy search form
- two h:selectOneMenu components are declared inside a form
- the second selectOneMenu, is refreshed base on selecting an item of the first selectOneMenu (with ajax)
For this, i use a central Bean in request scope, because the two selectOneMenus are declared on many other pages, so i dont need to define the two following methods multiple times:
pageSupport:
#SuppressWarnings("unchecked")
public List<BranchenRubrik> getLst_branchenRubrik() {
if(lst_branchenRubrik == null) {
Session session = hibernate.InitSessionFactory.getInstance().getCurrentSession();
Transaction tx = session.beginTransaction();
this.lst_branchenRubrik = session.createQuery("from BranchenRubrik").list();
tx.commit();
}
return lst_branchenRubrik;
}
// Loading Subkats with parameter
#SuppressWarnings("unchecked")
public List<BranchenRubrikSub> getBranchenRubrikSub(long p_parent) {
List<BranchenRubrikSub> lst_branchenRubrikSub = new ArrayList<BranchenRubrikSub>();
if(p_parent > 0) {
Session session = hibernate.InitSessionFactory.getInstance().getCurrentSession();
Transaction tx = session.beginTransaction();
lst_branchenRubrikSub = session.createQuery("from BranchenRubrikSub BRS WHERE BRS.parentRubrik.id = :p1").setLong("p1",p_parent).list();
tx.commit();
}
return lst_branchenRubrikSub;
}
VDL:
<p:selectOneMenu value="#{searchBean2.fvz.branchenRubrikID}">
<f:selectItem itemLabel="Bitte wählen" itemValue="0"/>
<f:selectItems value="#{pageSupport.lst_branchenRubrik}" var="rubrik" itemValue="#{rubrik.id}" itemLabel="#{rubrik.rubrik}"/>
<f:ajax render="uiBranchenSubKat"/>
</p:selectOneMenu>
<h:outputText value="Unterkategorie" />
<p:selectOneMenu id="uiBranchenSubKat" value="#{searchBean2.fvz.branchenRubrikSubID}">
<f:selectItems value="#{pageSupport.getBranchenRubrikSub(searchBean2.fvz.branchenRubrikID)}" var="brs" itemLabel="#{brs.rubrik}" itemValue="#{brs.id}"/>
</p:selectOneMenu>
this works fine, i can submit the form and all data are saved and will be re-displayed.
Now, i want to include an h:panelGroup with binding to a methode, which build a pagination menue.
If i include the h:panelGroup binding="#{searchBean2.paginationMenu}"/> then, i cant submit the form, because it says that the value for the second h:selectOneMenu is not valid.
if i remove the "h:panelGroup binding" all working as expected.
The h:panelgroup can also binded to an empty methode "return new HtmlPanelGroup()"
then, the error occurs again.
looks like, that the component binding, breaks some validation.
thanks for your time

View scope reset fields to default after performing an action

First of all, my beans are managed by spring not by JSF and I am using custom view scope as described in this article. So if the behavior is weird for regular JSF2 and might be related to Spring, please tell me.
Bean:
public class DepartmentBean {
private DefaultTreeModel model;
public void preRender(ComponentSystemEvent event) throws Exception {
if (model == null) {
model = myService.buildModel();
}
}
public String clear() {
// resetting stuff
return "pretty:";
}
}
View:
<h:form>
<ice:panelGroup styleClass="crud-links">
<h:commandLink value="Delete" action="#{department.deleteDepartment}" />
</ice:panelGroup>
</h:form>
<h:form>
<ice:panelGroup>
<ice:tree id="tree" value="#{department.model}" var="item" hideRootNode="false" hideNavigation="false" imageDir="./xmlhttp/css/xp/css-images/">
<ice:treeNode>
<f:facet name="content">
<ice:panelGroup style="display: inline">
<ice:commandLink value="#{item.userObject.text}"></ice:commandLink>
</ice:panelGroup>
</f:facet>
</ice:treeNode>
</ice:tree>
</ice:panelGroup>
</h:form>
When page is loaded for first time the model object is populated with data, but when clicking delete button I notice that after clearing preRender() method is executed and the model (which was populated before clearing becomes null, and gets populated again, although I am in same page, and it should maintain the value)
Does the code have a problem that leads to such behavior, or this is the normal behavior?
If the problem maybe related to Spring or the custom view scope or the IceFaces, please advise.
UPDATE- REQUIREMENT:
I want to initialize the tree model on construction of the page, and while i am still on the page the tree model doesn't gets initialized again until i do that programatically .
oh my mistake, initialization should be inside #PostConstruct.

Resources