JSF immediate="true" for cancel button doesn't work - jsf-2

I have a two tab page, one tab is the record list, click on the record will switch to the Edit tab, and there's Save and Cancel buttons in the Edit tab.
Now, I click on the record #1, do some edit, and click the Cancel button. Certainly I don't want to validate the form because it's canceled, so I set immediate="true" on the Cancel button. Now the edit tab is closed, back to the record list. Then, I click on another record #2, the problem occurred: In the edit tab, it's still the previous content of record #1, rather then record #2. I've checked the variables in debug view, the back bean for the edit form was ACTUALLY filled with record #2.
I.e., something broken after an immediate command.
(Everything had been well before I have added the validation and immediate="true".)
class FormBean {
Record activeRecord;
...
public void clickOnList() {
activeRecord = loadRecord(clickIndex);
}
public void cancelForm() {
activeRecord = null;
}
}
page.xhtml:
<h:form id="main">
...
<p:tab title="Edit" rendered="#{formBean.activeRecord != null}">
...
<p:commandButton value="Cancel"
actionListener="#{formBean.cancelForm}"
update="main" async="true" immediate="true" />
</p:tab>
</h:form>

The immediate="true" doesn't work nicely with ajax requests on the same view. It boils down to that the submitted-but-not-validated values are still there in the input components. Without ajax, a normal synchronous request/response of a subsequent form submit would silently "solve" this. But with ajax, this does not happen. The submitted values of the previous ajax request are still there in the input components. When UIInput#getSubmittedValue() doesn't return null, it will be displayed instead, irrespective of the (changed) model value.
Basically, when you want to stick to ajax for a cancel button, you need to exclude the inputs from being processed instead of relying on the immediate="true" (which is actually kind of a hack). In standard JSF <f:ajax> terms, you could do this with execute="#this" (which is actually the default) on the button instead of execute="#form". The PrimeFaces buttons defaults to #form, so you need to change this:
<p:commandButton value="Cancel"
actionListener="#{formBean.cancelForm}"
update="main" async="true" process="#this" />

Related

Error when calling a method with a4j:poll vs. JSF commandButton

I'm trying to implement an autoSave function on an edit form using a4j:poll.
My JSF page contains two items that call the same form method: a button and an RichFaces a4j:poll. The button functions properly. The poll fails. The symptom is that when the a4j:poll triggers, the data entity contained in the form is empty. When the button is pressed, the data entity contained in the form has that data that was typed into the fields.
<h:form id="patient">
<h:commandButton
styleClass="submit"
id="saveInProgress"
type="submit"
actionListener="#{sessionState.pForm.saveInProgressAction}"
value="Save In-Progress" />
<a4j:poll
interval="300000"
id="autoSave"
actionListener="#{sessionState.pForm.saveInProgressAction}" />
</h:form>
EDIT(3):
(Other edits removed, since they are no longer relevant.)
I think what is happening is that when the a4j:poll triggers, processUpdates() never gets called.
How can I call the processUpdates() method from the a4j:poll?
Edit:
Can I call processUpdates() from the method I call in the a4j:poll, saveInProgressAction() in this case?
By default only the poll component is processed on the server, if you need to process other components (e.g. text fields) you need to use #execute:
<a4j:poll execute="#form" />
this will process the entire form, but you can use ids if you need it to be more specific.

How to hide components by selecting a new value on h:selectOneMenu?

I have a page with a h:selectOneMenu, and I want to hide a dataTable when I choose a new value on the h:selectOneMenu while some bean attribute values update. I'm trying diferent things, and I'm able to hide the dataTable by reloading the page. I have tried this using some JavaScript code, on onsomething attributes. In that case, those bean attribute values disapear although I use t:saveState (and I also need the view scope for the bean).
Here is a little example to clarify this:
<h:selectOneMenu id="list" value="#{Bean.id}">
<f:selectItems value="#{Bean.List}" var="element" itemLabel="#{element.name}" itemValue="#{element.id}"/>
<t:saveState value="#{Bean.id}"/>
<f:ajax listener="#{Bean.populateBean}" render=":form:period" event="change"/>
</h:selectOneMenu>
<h:selectOneMenu id="period" value="#{Bean.period}">
<f:selectItems value="#{Bean.listaPeriod}" var="period" itemLabel="#{period[1]}" itemValue="#{period[0]}"/>
<t:saveState value="#{Bean.period}"/>
</h:selectOneMenu>
<h:commandButton id="search" action="#{Bean.doSearch}"></h:commandButton>
<t:dataTable id="data" value="#{Bean.configList}" rendered="#{Bean.search}"
<t:column>
...
</t:dataTable>
And Bean.doSearch changes Bean.search to true. How can I hide the dataTable when I choose a new value on h:selectOneMenu id="list"?
EDIT:
In short, the search button renders the table, and I would want to hide that table when I just choose a new value on the "list" dropdown without reloading the page. Now, the <f:ajax> is used only to rerender the "period" dropdown value.
Thanks in advance!
Your question is hardly understandable, but if you want to kick the datatable out of your view on ajax request triggered by your dropdown, you need to enclose it in a component that's always present in the view so that HSF would know what to rerender when ajax call successfully finishes:
<h:panelGroup id="rerender">
<t:dataTable rendered="#{bean.condition}" ...>
....
</t:dataTable>
<h:panelGroup>
Of course, to get it working you should specify id of the component to be rerendered:
<h:selectOneMenu ...>
...
<f:ajax listener="#{bean.populate}" render="rerender" />
</h:selectOneMenu>
Note that if both dropdown and datatable components belong to the same form, it's not necessary to specify absolute id of the latter's parent. Also note that specifying event is redundant, as it already defaults to the right one. Finally, as you're on JSF 2.x, using save state is not necessary, just bind the values of your form data to a view scoped bean.
The last thing to note is the fact that you fail to conform to the Java Naming Conventions, the thing you should correct as soon as possible.

JSF 2 + Primefaces: Need to update bean property on menu click before rendering dialog

I have a p:menuitem that needs to (1) update a backing bean property when clicked, and then (2) show a p:dialog.
This is the set up I have:
<p:menuitem value="Show Dialog"
oncomplete="dialog_widget.show();"
update=":dialog"
actionListener="#{bean.setCurrentAction}">
</p:menuitem>
<p:dialog widgetVar="dialog_widget" id="dialog" dynamic="true">
<h:form>
<p:inputText value="#{bean.record.text} />
// the proper rendering of this dialog form depends on bean.currentAction
// being set during JSF Phase 4 Update Model Values
</p:dialog>
And the backing bean:
public R getRecord() {
if (currentAction == null) {
return null;
}
return currentAction == NEW ? newRecord : selectedRecord;
}
The problem is that actionListeners and actions are only executed during Phase 5 and I need the bean.currentAction to be set before that so the dialog can be properly updated and rendered.
** A little background on what I'm trying to achieve: the dialog form is used to Create new records as well as Update exsiting records (Add and Edit Dialog). So the "currentAction" on the bean indicates which action the user is doing. Depending on which action, the form needs to use different model objects ("newRecord" or "selectedRecord") to pull and save the form data to.
Although not a very elegant solution you can use PrimeFaces' RequestContext's update method to set update target and use the execute method to show your dialog in your actionListener after setting the needed property.
If you requirement is to call the backing bean method before the dialog opens then you can go for a ajax function (i don't know whether you are allowed to use ajax in your application). for p:menuItem there is a function called onclick, where you can call a a4j:ajax function through which you can call a backing bean method and update the model before dialog opens.
By default action is called during "Invoke Application" phase. You can add immediate="true" attribute in p:menuitem tag. This will call action in "Apply Request Values" phase.

JSF: setting a property in a wizard form with multiple submit actions

I have this scenario: in the first tab of a primefaces wizard component, I have some fields and a button. The button saves some data, does some business logic and, with the results, sets some properties of the form bean (which is in ViewScope) that are not related to a specific field of the form. I have checked that in the invoke application phase, the values are set properly.
In the second tab I have another button that has to do some business logic using the values set by the first one but, doing some debug, I noticed that the values, even if not related to any field of the form, are overwritten I think during the update model phase invoked when I click the second button.
How can I avoid this? Is there a way to obtain the correct behaviour?
I looked around but I couldn't find any example of a wizard form with multiple submissions. Thanks for help!
<p:wizard widgetVar="wiz" render="true" id="wizard" showNavBar="false">
<p:tab id="step0" title="Step0" step="0">
<!-- Some other fields-->
<p:commandButton value="Save and do some business logic"
action="#{formBean.save}"
oncomplete="wiz.loadStep (wiz.cfg.steps [1], false)">
</p:commandButton>
</p:tab>
<p:tab id="step1" title="Step1" step="1">
<!-- Some other fields-->
<p:commandButton value="Second button: use the previous informations"
action="#{formBean.doSomething}"
oncomplete="wiz.loadStep (wiz.cfg.steps [2], false)">
</p:commandButton>
</p:tab>
</p:wizard>
Edit:
To show an example I can say that my bean contains a business logic object. During the first submission, this object is being saved so the database (Mysql and Hibernate), assigns to it a progressive id.
During the second submission, when I try to read this id, the value is zero so, obviously, I get an error.
Something like:
public class FormBean{
private BLObject object;
// Constructor Getters and setters
// Method executed during the first submission
public void save(ActionEvent actionEvent) {
//Save the object and set his id
PersistanceClass.getInstance().save(object);
}
// Method executed during the second submission
public void doSomethingWhitTheId(ActionEvent actionEvent) {
//Access the id... id=0 returned
int id = object.getId();
}
}
The problem was that, navigating from one page to another, Primefaces wizard, uses a String to identify the tab. Returning the value of this String, which is not null nor void, makes the view bean go out of scope. It is ok when you have a simple form but, if you wanna set some properties not related to a form element during the flow, they get overwritten during the tab changes.
I solved the problem adding to the form an hidden parameter linked to the property I wanted to preserve.
<h:inputHidden value="formBean.idToPreserve" id="inputHidden" />

PrimeFaces Ajax Listener not executed when process attribute is specified for a different component

When I specify process attribute of p:ajax tag, the listener is not executed. If I omit the process attribute, then the listener is called as expected.
Here is the view snippet:
<p:messages id="messages" />
<h:inputText id="inputToProcess" value="#{controller.inputToProcess}" />
<p:selectBooleanCheckbox id="testCheckbox" >
<p:ajax event="change" process="inputToProcess"
update="messages #this inputToUpdate"
listener="#{controller.processChecked}" />
</p:selectBooleanCheckbox>
<h:inputText id="inputToUpdate" value="#{controller.inputToUpdate}" />
And Controller:
#javax.faces.bean.ManagedBean
#javax.faces.bean.ViewScoped
public class Controller implements Serializable {
private String inputToProcess;
private String inputToUpdate;
//getters and setters
public void processChecked(javax.faces.AjaxBehaviorEvent e) {
// doing some stuff here
}
}
I attached a phaseListener to a view with ANY_PHASE PhaseId, and here is what I observed.
When I specify process attribute , the value of the inputToProcess input is successfully set to the controller during the Update Model phase (no exception occurs). Then the Invoke Application and Render Response phases are executed, but no listener is called. One thing I noticed is that checkbox is not set in the end. But, there are no conversion or validation errors, because as I said the Update Model and Invoke Application phases are executed.
If I omit process attribute, here is what I see: the listener is normally called during the Invoke Application phase (since immediate is false by default), and then `Render Response is executed. Checkbox is successfully set.
Is there any explanation for this sort of behavior?
It should work fine at first sight. At least, it works fine that way when using standard JSF components. I'd bet it to be a bug or "feature" of PrimeFaces that it doesn't process the action when the action component is not included in the process. Adding #this to process should solve it. Consider posting an issue report to PrimeFaces guys.
Further, I'd rather use event="valueChange" or event="click" instead of event="change" or just remove the event altogether, it defaults to the right value already (valueChange which will render onclick in checkbox and radio button components). The change event works differently in MSIE for checkboxes and radiobuttons. It's only triggered on 2nd click and forth. You don't want to be browser dependent.
As per your comment:
The problem with the standard JSF checkbox and ajax components, is that the listener is invoked during Process Validations phase, but I need to update the model first!
This is not true. Probably you was using valueChangeListener instead of <f:ajax listener> or confusing the one with the other. The <f:ajax listener> is always invoked during invoke action phase.

Resources