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.
Related
I create page forms with a parameter that tells them where to return when done. The backing bean is #ReqeuestScoped and includes this:
<f:metadata>
<f:viewParam name="return" value="#{createGroup.paramReturn}" />
</f:metadata>
The form has fields with validators, so the cancel button has to skip validation. So, the cancel button looks like this:
<p:commandButton value="Cancel"
action="#{createGroup.doCancel}"
immediate="true"
/>
The purpose of the doCancel() method is to go into Flash scope and return the value set with setParamReturn method.
The problem is with the immediate="true" attribute is that the Flash storage that has the paramReturn variable in it is no longer available. If someone could tell me how to fix that this would be my preferred solution.
Of course without the immediate="true" attribute the action is never invoked because the form cannot pass validation. Another solution would be to cause validation to be ignored some other way.
I have looked at the OmniFaces <o:ignoreValidationFailed> tag and it seems to do what I want, but I don't want to import a whole library for just this tag. However, that is what I will do if there is no other simple way to fix this.
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.
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" />
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.
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" />