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.
Related
So I have this code:
<h:form id="serviceCustomFormForm">
<p:dialog id="parameterGroupAddDialog" widgetVar="parameterGroupAddDialog" header="#{messages.addParameterGroup}" modal="true" resizable="false">
<p:inputText value="#{serviceCustomFormBean.serviceParameterGroup.name}" styleClass="Wid90" />
<br />
<br />
<p:commandButton value="#{messages.save}" styleClass="Fright BlueButton" update="serviceCustomFormForm" actionListener="#{serviceCustomFormBean.addServiceParameterGroup}" oncomplete="PF('parameterGroupAddDialog').hide()" />
<p:commandButton value="#{messages.cancel}" styleClass="Fright RedButton" oncomplete="PF('parameterGroupAddDialog').hide()"/>
</p:dialog>
<div class="Container100">
<div class="ContainerIndent">
<p:commandButton value="#{messages.addParameterGroup}" icon="fa fa-plus-circle" styleClass="Fright CyanButton FloatNoneOnMobile" oncomplete="PF('parameterGroupAddDialog').show()" />
<div class="EmptyBox10 ShowOnMobile"></div>
</div>
</div>
</h:form>
When the page is first loaded the #PostConstruct method is called.
When I click the commandButton to open the dialog it's called again. And when I press the Cancel button inside the dialog it's called again.
This behavior does not occur in other parts of the application, and I can't see what I am missing here.
Update: As requested, the Bean code is here:
#ManagedBean
#ViewScoped
public final class ServiceCustomFormBean implements Serializable {
private ServiceParameterGroup serviceParameterGroup = new ServiceParameterGroup();
// Other attributes
#PostConstruct
private void init() {
// Reads attributes sent from previous page
}
public void addServiceParameterGroup() {
// Saves the serviceParameterGroup to database
}
// Getters and Setters
}
It's because the Commandbutton submits the form. You can
change to this:
<p:commandButton type="button" ...onclick="PF('parameterGroupAddDialog').hide()"
Type button tells primefaces not to submit the form. If the form isn't submitted oncomplete is never called. So it's onclick.
Try setting the following attributes to your 'Add Service' and 'Cancel' commandButton elements: partialSubmit="true" process="#this".
Code like this:
<commandButton value="#{messages.addParameterGroup}" ... partialSubmit="true" process="#this" ... />
By default, pf commandButtons try to submit the whole form, while in those two cases you just want to call the invoked method without doing a submit. With this, you are saying to primefaces that you don't want to submit it all (partialSubmit=true), and that you just want to process the invocation of the button itself (process=#this). Maybe that is your problem.
As an additional comment, i don't think getting the label values for the buttons from the bean is a good idea (unless you want to intentionally change the labels dynamically), because you will end up doing excessive requests to the bean. Better try using a messages properties file, as described in here http://www.mkyong.com/jsf2/jsf-2-0-and-resource-bundles-example/.
If I remember correctly, you should put your Dialog outside your main form, at the end of your body or use the appendTo="#(body)" param, and then, have another form inside the dialog.
After a long time dealing with this problem, I finally found the reason.
The annotation ViewScoped that I was importing in the backing bean was from the package javax.faces.view.
The correct one is javax.faces.bean.
Thanks for everyone that spend some time trying to help.
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()?
I have a simple form.
<h:form>
<h:selectOneMenu value="#{user.siteID}" >
<f:selectItems id="vals" value="#{user.basinSiteIDs}" />
<f:ajax event="valueChange" listener="#{user.updateWithAjax(e)}"
render="all" />
</h:selectOneMenu>
<h:selectManyCheckbox id="all" value="#{user.siteIDs}" layout="pageDirection">
<f:selectItems id="sites" value="#{user.csrpSites}" />
</h:selectManyCheckbox>
<h:commandButton value="submit" action="result"/>
</h:form>
The page initially loads with a drop down and check boxes with associated values. When I make a selection from the drop down, the check box values are changed dynamically with ajax. I need to click submit button and display the user selected values in result page.
Here is the problem:
If I use #RequestScoped, clicking the submit button gives j_idt7:all: Validation Error: Value is not valid.
#ViewScoped, takes to result page but with empty/null values.
#SessionScoped, shows result page with correct values but they are gone when I click browser's back button and land in the index page. This happens only under IE and Chrome but not in Firefox.
The #ViewScoped is the right scope for the purpose of having a dependent dropdownlist which is populated by ajax. Your concrete problem is caused by binding one same view scoped bean to 2 physically different views for some reason. A view scoped bean lives as long as the view itself. If you change the view, then you'll get a new view scoped bean. If you had shown the results in the same view, then it would have worked just fine.
If you really need to keep this odd approach of 2 physically different views, then your best bet is to split the bean in two:
<h:selectOneMenu id="basin" value="#{user.basinSiteID}" >
<f:selectItems value="#{data.basinSiteIDs}" />
<f:ajax listener="#{data.loadCsrpSiteIDs}" render="csrp" />
</h:selectOneMenu>
<h:selectManyCheckbox id="csrp" value="#{user.csrpSiteID}" layout="pageDirection">
<f:selectItems value="#{data.csrpSiteIDs}" />
</h:selectManyCheckbox>
<h:commandButton value="submit" action="result"/>
(note that I did some improvements here, your initial code was somewhat dirty and particularly the attempt to pass ajax behavior event is completely wrong, it would arrive as null)
The #{user} is here request scoped and #{data} is view scoped.
See also:
How to choose the right bean scope?
I have a <p:dialog> which contains a <h:selectOneMenu> with a valueChangeListener. Here's the relevant code:
<p:dialog>
<h:form>
<div>
<h:selectOneMenu value="#{itemController.itemId}" valueChangeListener="#{itemController.chkItemType}" onchange="submit()">
<f:selectItems value="#{itemController.itemsList}" />
</h:selectOneMenu>
</div>
</h:form>
</p:dialog>
When it is called, the dialog get closed. I would like to keep it open and only close it on cancel button. How can I achieve this?
That's expected behaviour. The onchange="submit()" which you've there submits the entire form synchronously, causing a complete page reload.
You should be using ajax instead to perform the submit. Replace the onchange attribute by just this tag
<f:ajax />
inside the <h:selectOneMenu>. This way the form will be submitted asynchronously, with by default no page reload at all.
Depending on the concrete functional requirement, which you didn't tell anything about, you do probably also not need a valueChangeListener at all, but rather a <f:ajax listener>.
<f:ajax listener="#{itemController.chkItemType}" />
If you'd like to update some parts of the page on successful execution of the ajax request, use its render attribute.
See also:
When to use valueChangeListener or f:ajax listener?
I have a a button that is setting a property to a backing bean to be used in Primefaces Dialog.
p:commandButton value="Options" onclick="optionsDialog.show();">
`<f:setPropertyActionListener value="#{item}" target="#{bean.tempItem}" />
</p:commandButton>
I can see that setter is called here.
<p:dialog header="Options" widgetVar="OptionsDialog" dynamic="true" modal="true"
width="400" height="250">
<h:outputText value="#{bean.tempItem.value}"/>
</p:dialog>
Here the getter is never called.
That's because the dialog's content is not been updated before you show it. You need to update it by update attribute of the command button. Reference the (relative) client ID of the dialog in there. You also need to replace onclick by oncomplete because the onclick fires before the action is performed and oncomplete fires after the action is performed.
<p:commandButton ... update="dialogId" oncomplete="optionsDialog.show();">
...
<p:dialog id="dialogId" ...>
You've by the way also a lowercase/uppercase typo in the dialog widget name. But that would cause the dialog to not show up at all, which is a different problem.