p:dialog form submit loses action method after RequestContext update - jsf

I have a small form inside my p:dialog:
<p:dialog id="commentDialog" header="#{managedBean.dialogHeader}" widgetVar="commentDialog" modal="true" resizable="true" height="auto">
<h:form>
<h:outputLabel for="comment" value="Comment:"/>
<p:inputTextarea id="comment" title="Comment"
rows="6" cols="33"
value="#{managedBean.comment}"
required="true"/>
<h:commandButton value="Submit" action="#{managedBean.dialogFormSubmit}"/>
</h:form>
</p:dialog>
Can you tell why, when I hit the Submit button, the dialog does get closed but the dialogFormSubmit() in the managed bean does not get invoked?
I also tried changing to p:commandButton thinking the functionality required the PrimeFaces variant of the h:commandButton but got the same.
The question is similar to this and I tried to do the same but couldn't make it work and also this one which doesn't really seem to have a workable answer.
UPDATE:
The dialog was being shown from the managed bean but was also updated (the solution for which I got here) prior to showing by using the RequestContext API in order to refresh the header:
RequestContext context = RequestContext.getCurrentInstance();
context.update("commentDialog");
context.execute("PF('commentDialog').show();");
I have come to realize that this malfunction occurs only when I update the dialog (middle line above). When I actually don't (which is not critical for the dialog functionality but the header appears blank), the submit action works fine. So the context update seems to be what's messing it up and I don't know how to get both the update while retaining the submit functionality. Could it be a bug in RequestContext.update()?

Related

primefaces p:inputSwitch not work in dialog while use update the dialog

I am doing a on-off with p:inputSwitch, it's in a dialog. When an ajax call inside a form happens in combination with an update on the inputSwitch, the inputSwitch behaves strange and always resets its state. Here is a simple reproducible example (without the need of a backing bean):
<h:form id="buttonForm">
<p:commandButton value="button" update="switch" oncomplete="PF('switchDialog').show();" />
<p:dialog widgetVar="switchDialog">
<p:inputSwitch id="switch" />
</p:dialog>
</h:form>
Interesting observations:
When you remove the h:form the problem is gone
When you remove the update parameter it works
When the p:inputSwitch is outside of the p:dialog it also works
Sorry for this zombie post but i've found a solution that can help.
Add in your
<p:dialog widgetVar="switchDialog" dynamic="true">
Regards

Update JSF messages after initial rendering via p:menuitem

Does anyone know if it's possible to update a JSF message or messages element AFTER its initial rendering via PrimeFaces' p:menuitem?
For example, I have a PrimeFaces p:menuitem I am using to open a p:dialog, and that p:dialog has a p:messages element whose message I would like to update and show the moment that the p:dialog is opened - I can't know whether there is a message I want to show or what that message should be until after the p:menuitem's action method is complete.
Unfortunately, setting the update attribute of the p:menuitem to both the id of the p:dialog and the id of the p:messages element itself does not cause the p:messages element to show its message, even though I think it should since the action method of the p:menuitem looks like it is properly adding a message to the p:messages element.
The menuitem opening the dialog:
<p:menuitem value="Show Dialog with Message" action="#{myView.prepareDialogWithMessage()}" oncomplete="PF('dialogWidget').show()" update="dialogWithMessage message" />
The dialog with the message:
<p:dialog id="dialogWithMessage" widgetVar="dialogWidget" resizable="false" dynamic="true" closable="false" showEffect="fade" hideEffect="fade">
<p:messages id="message" for="message" showDetail="true" escape="false" autoUpdate="true"/>
<div class="button-panel">
<p:commandButton value="Yes" styleClass="ui-confirmdialog-yes" action="#{myView.submitAction()}" oncomplete="PF('dialogWidget').hide();"/>
<p:commandButton value="No" styleClass="ui-confirmdialog-no" onclick="PF('dialogWidget').hide();"/>
</div>
</p:dialog>
The Java code which adds the message:
public void prepareDialogWithMessage() {
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_WARN, "Summary of message we want to show when the dialog opens", "Details of the message we want to show when the dialog opens");
FacesContext.getCurrentInstance().addMessage("message", message);
}
Short answer: It behaves exactly as expected and implemented.
Longer answer:
Having a closer look after your edited question, I noticed the dynamic="true" on the dialog. If you read the PrimeFaces docs it states (as you already found out):
dynamic: Enables lazy loading of the content with ajax.
So when you show the dialog via javascript, its content is updated... Since this content also includes the p:messages, that is also updated. In your case updated again with the messages that are generated in the ajax call of the update of the dialog... Most likely none... So the messages you added to it in the prepareDialogWithMessage() call of the menuItem are lost.
Since you already update the dialog in the call to the menuItem, the dynamic='true' is totally superfluous and it throws a spanner in the works.
<off-topic>A suggestion is to always start creating an [mcve]. Removing more and more until the behaviour of certain parts is as expected. Removing the dynamic='true' in one of the steps would have resulted in this and you'd have known a lot more. At the same time, also try debugging more. Investigating by looking at the requests and responses in the browser developer tool. You would have seen the messages getting added to the dialog and then the dialog(contents) being totally overridden. All these things are easy too (sorry, easy instead of 'not to difficult), can/will tell you a lot and helps getting to the cause of things quicker. Either directly, or by being able to ask way more specific question that is often easier to answer</off-topic>

View scoped managed bean's #PostConstruct reinvoked after closing p:dialog

I have a popup defined within my XHTML which gets shown conditionally depending on what selections the user makes in the main screen rendered by default:
<p:dialog id="commentDialogID" header="Enter comment" widgetVar="commentDialog" modal="true" resizable="true" height="auto">
<h:form id="commentForm">
<h:outputLabel for="comment" value="Comment:"/>
<p:inputTextarea id="comment" title="Comment"
rows="6" cols="33"
value="#{managedBean.activeItem.comment}"
required="true">
<f:ajax render="comment"/>
</p:inputTextarea>
<h:commandButton id="commentSubmit" value="Submit" action="#{managedBean.proceed}" onclick="PF('commentDialog').hide();">
<f:ajax render="commentSubmit"/>
</h:commandButton>
</h:form>
</p:dialog>
The problem is that, once this dialog/popup is closed, the container (JBoss) or the framework (JSF/Primefaces), not sure which, thinks that the whole view has been closed and therefore on the next request that triggers an appearance of this popup, it re-invokes the backing bean's #PostConstruct method. The backing bean is #ViewScoped. I really don't want it to do that, instead, I want it to treat the dialog/popup as a div in the page whose closure does not affect the view state.
The first time the dialog is brought up, the #PostConstruct is not invoked as the initial view from rendering the page, which called the #PostConstruct, is still active. However, on the second appearance, it is reinvoked, which leads me to believe it is because it was closed after the first time, which either the container of the framework or both mistake as needing to reload the bean.
What can I do to prevent the backing bean from going into the #PostConstruct after this dialog has been closed?
I know what the problem is..
You are using h:commandButton to submit the form and to close the dialog.
Lets look at your code:
<h:commandButton id="commentSubmit" value="Submit" action="#{managedBean.proceed}" onclick="PF('commentDialog').hide();">
<f:ajax render="commentSubmit"/>
</h:commandButton>
In the above code As soon as you clikc Submit button:
1. Your action will get triggred to call ManagedBean method managedBean.proceed.
2. since you have bound onclick JS event, your dialog gets closed.
After your action="#{managedBean.proceed} comes back it has to update the button with id commentSubmit since you have used render="commentSubmit".
But by the time your action="#{managedBean.proceed} comes back to render="commentSubmit" the disloag in which your button commentSubmit is placed is closed. so this might the reason for re initializing the ManagedBean.
To Avoid this you ca use Primefaces p:commandButton which has oncomplete attribute which is helpfull in this scenario.
<p:commandButton id="commentSubmit" value="Submit" action="#{managedBean.proceed}" update="commentSubmit" oncomplete="PF('commentDialog').hide();" />
So in the above case p:dialog will close after the action is completed.

ui:repeat with a list sending right object to a p:dialog

I currently have a giant ui:repeat. Within this ui:repeat, some of the repeated objects have a url to a popup image associated with them. When someone clicks display under that particular object, I need the url to popup in a p:dialog.
<ui:repeat var="thing" value="#{bean.thingList}">
<p:commandLink value="details" onclick="miniImage.show();"
update=":#{p:component('chart')}"
action="#{bean.setCurrentImg(thing.imageUrl)}"
rendered="#{thing.includeImage}">
</p:commandLink>
</ui:repeat>
and at the bottom of the page:
<p:dialog id="chart" widgetVar="miniImage" >
<h:graphicImage value="#{bean.currentImg}"/>
</p:dialog>
And in the backing bean I tried using a simple setter and getter for currentImg.
I am a bit confused on this now and would like to accomplish this without having to submit the entire form as well. Any help is greatly appreciated.
If you're using PrimeFaces 3.3 or newer, you could just add partialSubmit="true" to the command component. You can then control the to-be-processed components in process attribute. In this particular case, just the current component (the command component itself) is sufficient, thus so process="#this":
<p:commandLink ... process="#this" partialSubmit="true" />
This way only the request parameters which are really necessary for the process will be sent.
Unrelated to the concrete problem, I suggest to use oncomplete instead of onclick to open the dialog. Otherwise the dialog is opened before update takes place and may cause poor user experience as the enduser would see the image instantly changing.

Why does p:resetInput require properties of a managed bean to be set to null first after the form is submitted?

In a view scoped managed bean, I'm using <p:resetInput> to clear the values held by the properties in the corresponding manged bean like,
<p:commandButton value="Reset" update="panel" process="#this">
<p:resetInput target="panel" />
</p:commandButton>
This works fine.
I have a submit button <p:commandButton> which when pressed causes the submitted values to be inserted into the database, if validation succeeds.
<p:remoteCommand name="updateTable" update="dataTable"/>
<p:panel id="panel" header="New">
<p:outputLabel for="property1" value="property1"/>
<p:inputText id="property1" value="#{bean.property1}" required="true">
<f:validateLength minimum="2" maximum="100"/>
</p:inputText>
<p:message for="property1" showSummary="false"/>
<p:commandButton id="btnSubmit"
update="panel messages"
oncomplete="if(!args.validationFailed) {updateTable();}"
actionListener="#{bean.insert}"
value="Save"/>
<p:commandButton value="Reset" update="panel" process="#this">
<p:resetInput target="panel" />
</p:commandButton>
</p:panel>
The command button invokes the insert() method in the managed bean which is defined as follows.
public void insert() {
if (service.insert(property1)) {
//...Popup a success message.
reset(); //Invoke the following private method.
} else {
//...Show the cause of the failure.
}
}
private void reset() {
property1 = null; //Set this property of type String to null.
}
If this reset() method is omitted, then <p:inputText> will not be cleared as obvious but then if I press the reset button as shown in XHTML, <p:inputText> should be cleared but it doesn't.
The showcase example demonstrates exactly the same thing. Therefore, this behaviour appears to be documented but I don't understand why doesn't <p:resetInut> clear the value of property1, if the reset() method is omitted, in this case?
The <p:resetInput> does not clear the model values as you incorrectly seemed to expect. It just clears the input component's state which may be dirty after a validation error.
The concrete problem it is trying to solve is in detail described in this answer: How can I populate a text field using PrimeFaces AJAX after validation errors occur?
This is the best understood by the following use case:
You have a single view with a single datatable and a single dialog which displays the currently selected record for editing.
You open the dialog and submits its form with invalid values. The input components are marked invalid and highlighted red.
You close the dialog without fixing the errors.
Then you select same or another row for editing. The dialog shows up, but the input components are still marked invalid and highlighted red and show the old submitted value -if any- because it's still the same view state you're working with.
Putting <p:resetInput> with target on dialog's form in the "open dialog" button fixes it.
I'm not sure if your particular case is the right use case for which <p:resetInput> is the right solution. Your code is not complete and you didn't state the concrete functional requirement behind this code anywhere, but as far as I see, there are no multiple inputs/forms which need to update each other. I believe that your case would still work even if you remove <p:resetInput>. So it would be totally superflous in your context and you could just get away with clearing the model (or.. just with refreshing the page by a synchronous GET button which implicitly recreates the view).
See also:
PrimeFaces CommandButton that Doesn't Process Data
Escape a primefaces/jsf page that has required fields

Resources