I am getting confused on the constrcut of a Primefaces 3 dialog.
I see question in SO that has this pattern. The form is outside the dialog.
<h:form>
<p:dialog id="dialog" modal="true" widgetVar="dlg">
</p:dialog>
</h:form>
But other question has this.
<p:dialog id="dialog" modal="true" widgetVar="dlg">
<h:form>
</h:form>
</p:dialog>
The Primefaces showcase http://www.primefaces.org/showcase/ui/dialogLogin.jsf favors the latter one.
I am getting confused if there's any valid reason for using the one over the other?
Thanks
You always better use place the <h:form> inside <p:dialog like this
<p:dialog id="dialog" modal="true" widgetVar="dlg">
<h:form>
</h:form>
</p:dialog>
cause you dialog content might be "taken" out from your page and appended some where else in your DOM tree , so if you place the dialog inside some form, it can cause your dialog to be relocated somewhere else and to cause all your buttons/links and other elements to stop working (this is a very common question here in SO)
So in order to be allays on the safe side place you <h:form> tag inside your <p:dialog tag
Another example is when you use appendToBody="true" in dialog :
if dialog is inside an h:form component and appendToBody is enabled, on the browser
dialog would be outside of form and may cause unexpected results. In this case, nest a form inside
a dialog.
Related
I have a form (frmAddPax) to add some users data. This data could be submited manual or vía a barcode reader. When the button "Escanear" is pressed this one calls a dialog with another form (frmScan).
This form read some data from a barcode reader and this data is processed in the managed bean. The data creates an object that is used in the original form (frmAddPax).
The problem is all the form has the styling as there wasn't any data on it, all the mandatory fields have the required="true" attribute.
If I press the "Escanear" button again and scan the same data it shows the form just fine.
I think this could be because before the data is ready updated in the form the validation process happend, but as I have seen in some questions the action and actionListener events happend before the update process so I have no clue.
This is the code of the form:
<h:form id="frmAddPax"
rendered="#{MB.renderStatus.isRenderFormAddPax()}">
<p:panelGrid styleClass="no-border">
<p:row>
<p:column>
<h:outputText
value="#{label['manageVipLoungeEntrance.addPassenger.firstName']} />
</p:column>
<p:column>
<p:inputText required="true"
value="#{manageVipLoungeEntranceExtMB.passenger.firstName}"
style="text-transform: uppercase;" converter="upperCaseConverter">
<f:ajax event="blur" update="#this" render="#this" />
</p:inputText>
</p:column>
...
...
<!-- BOTON ESCANEAR AGREGAR PASAJERO -->
<p:column>
<p:commandButton inmediate="true"
value="#{label['manageVipLoungeEntrance.addPassenger.button.scan']}"
onclick="showLocalDate()" update=":frmScan"
actionListener="#{manageVipLoungeEntranceExtMB.clear}"
oncomplete="{wgvScan.show()}" />
</p:column>
<!-- BOTON ESCANEAR AGREGAR PASAJERO -->
</p:row>
</p:panelGrid>
This is the code for the call that made the "Escanear" button:
<p:commandButton inmediate="true"
value="#{label['manageVipLoungeEntrance.addPassenger.button.scan']}"
onclick="showLocalDate()" update=":frmScan"
actionListener="#{manageVipLoungeEntranceExtMB.clear}"
oncomplete="{wgvScan.show()}" />
And this is the code for the widtget that process the barcode read and updates the original form with the data processed.
<p:dialog widgetVar="wgvScan" modal="true" showEffect="fade"
closeOnEscape="true" resizable="false">
<h:form id="frmScan">
<p:graphicImage value="../resources/images/barCode.png"
rendered="#{manageVipLoungeEntranceExtMB.showTablePassenger!=true}" />
<p:inputText id="itbarcode"
rendered="#{manageVipLoungeEntranceExtMB.showTablePassenger!=true}"
value="#{manageVipLoungeEntranceExtMB.barCode}" onfocus="true"
autocomplete="off" styleClass="insertData"
style="background:#ffffff; position:absolute;left:-7000;" />
<p:commandButton id="cmdReadBarcode" style="display:none"
onclick="showLocalDate()"
actionListener="#{manageVipLoungeEntranceExtMB.readBarCode}"
update=":frmAddPax :growl">
</p:commandButton>
<p:defaultCommand target="cmdReadBarcode" />
...
</h:form>
[EDIT]
#alibttb answer get me to the solution.
I added a remoteCommand before the button that calls the dialog to listen the scanner.
<p:remoteCommand name="refreshForm" process=":frmAddPax" update=":frmAddPax" />
<p:commandButton
value="#{label['manageVipLoungeEntrance.addPassenger.button.scan']}"
onclick="showLocalDate()" process="#this" update=":frmScan"
actionListener="#{manageVipLoungeEntranceExtMB.clear}"
oncomplete="{wgvScan.show()}" />
</p:column>
And in the dialog with the form that process the barcode I added a onHide attribute calling the remoteCommand.
I change the enclouse of the dialog-form to form-dialog as was sugested.
<h:form id="frmScan">
<p:dialog widgetVar="wgvScan" modal="true" showEffect="fade"
closeOnEscape="true" resizable="false" onHide="refreshForm()">
What happens when you click the Escanear button is that you are processing the whole form, thus submitting all the fields with empty values, this will cause validation errors, your button is immediate so what happens is the following:
actionListener is immediate so it's called first and the managed bean is filled with data from a barcode scanner.
the form data is being validated and it's not valid so the inValid flag is set on all the inputs.
the response is created on the server containing an update for the form, showing the new values from the managed bean and the inValid state of the inputs from the validation process.
notice that the submitted data (empty values) is not applied to the model as it's not valid.
to fix this, just use partial processing feature on your button, and remove the immediate="true", it's just a bad design.
just replace immediate="true" with process="#this" in the Escanear button.
If you're not familiar with partial processing feature of JSF and primefaces you should give it a look.
if you really need to submit the form for validation after the scan is complete then you need to use a p:remoteCommand that submits the form after the actionListener is complete:
<p:remoteCommand name="validateForm" process="#form"/>
<p:commandButton value="#{label['manageVipLoungeEntrance.addPassenger.button.scan']}"
onclick="showLocalDate()" update=":frmScan" process="#this"
actionListener="#{manageVipLoungeEntranceExtMB.clear}"
oncomplete="{wgvScan.show()}" />
and in the other form frmScan do:
<h:form id="frmScan">
<p:dialog widgetVar="wgvScan" modal="true" showEffect="fade"
closeOnEscape="true" resizable="false" onHide="validateForm()">
....
....complete your code
the name of the p:remoteCommand becomes a javascript function that can be called back once the scan dialog is hidden.
Note bring up the dev console in your browser and watch the two requests one for updating the form and closing the dialog and the other one caused by p:remoteCommand to validate the form.
Note 1 (not related to your question) that I used the frmScan to enclose p:dialog this is the right way to do it, the form should surround the dialog not the other way around.
I have a dynamic dialog
<p:dialog
dynamic="true"
closeOnEscape="true"
id="modalID"
modal="true"
>
<p:outputPanel rendered="#{empty testBean.someArrayList}">
empty
</p:outputPanel>
</p:dialog>
When I include this dialog on a page the testBean is not initialized - great, that is what I want. It is only initialized when I show the dialog.
However when I include a p:dataTable in the dialog:
<p:dialog
dynamic="true"
closeOnEscape="true"
id="modalID"
modal="true"
>
<p:outputPanel>
<p:dataTable rendered="#{not empty testBean.someArrayList}" value="#{testBean.someArrayList}" var="item">
<p:column>
#{item}
</p:column>
</p:dataTable>
</p:outputPanel>
</p:dialog>
The testBean is being initialised and testBean.getSomeArrayList() is called on the backing bean.
I have read that this is the case with ui:includes (see Launching dialogs using PrimeFaces via <p:dialog> and <ui:include>) but why is that the case with a p:dataTable? Btw. putting a rendered around the p:dataTable didn't fix the problem either.
What options do I have to not have testBean initialised straight away?
I could use c:if but from my experience you can get strange results when you mix JSTL and JSF. I normally only use it to exclude stuff that will not be rendered (even after some ajax requests). When I used it before with ajax it did sort of worked but could cause unexpected problems.
Another option I could see is to use ui:include with dynamic src e.g.
<p:dialog
dynamic="true"
closeOnEscape="true"
id="modalID"
modal="true"
>
<p:outputPanel id="updateMeWhenOpeningModal">
<ui:insert src="#{dialogManager.testBeanSrc}"/>
</p:outputPanel>
</p:dialog>
And then change the testBeanSrc from path to an empty file to a file containing the p:dataTable.
Are there any other solutions? Which one would have the least side effects?
I'm trying to update a primefaces dialog every time it pops up.
The dialog is triggered by a calendar field changing and the actual call is made from the bean.
When I call it the first time, the datas are fine but, if I close it and open it again, it'll still show the old datas.
It kinda makes sense: it's rendered just once and then it's shown and hidden and never actually updated.
I was thinking about updating it before the dialog.show() in the bean, but I don't know how to do that.
Any idea?
<p:dialog
site ="sectionDlg"
widgetVar ="Dlg"
minWidth ="430"
modal ="true"
closable ="true"
resizable ="false"
dynamic ="true"
width="450" height="300"
>
<h:form id="Form">
<br/>
<p:panelGrid id ="dates" styleClass="cmt-no-grid-100perc" columns="4">
<calendar attribName ="offerStartDateDlg"
value ="#{bean.startDate}"
writable ="#{false}"/>
<calendar attribName="offerEndDateDlg"
value="#{bean.endDate}"
writable="#{false}"/>
</p:panelGrid>
<div align="center">
<p:commandButton
onclick ="PF('whichSectionDlg').hide()"
>
</p:commandButton>
<p:commandButton
onclick ="PF('whichSectionDlg').hide()">
</p:commandButton>
</div>
</h:form>
This could make things easier
Ok so, I managed to figure it out.
I solved it by updating it from the bean, right before the call
public void show_dlg_method(){
RequestContext.getCurrentInstance().update("Dlg");
RequestContext.getCurrentInstance().execute("PF('Dlg').show()");
}
with "Dlg" being the widgetVar attribute value.
Some code of what you already have is always helpful. However, depending on what triggers the dialog to show up you can:
add an update to the triggering link/button/whatever or
initiate the update by the dialog itself like shown below.
<h:form>
<p:remoteCommand name="updateDialog" update="dialogpanelid" />
</h:form>
<dialog onShow="updateDialog">
<p:outputPanel id="dialogpanelid"> your content here </p:outputPanel>
</dialog>
Note that:
You need the remoteCommand to reside inside h:form
You should always update the dialogs content, not the dialog itself
the client-side id might differ depending on your page structure.
I have a datatable, with a command Button in each row,
The issue is that when i need to open one dialog for the first one, and then by clicking on another button, i need to update it. The issue is when i click on the second button, it closes the dialog and the user have to click once again on the second button to open the dialog again!
Thank's in advance for your help,
i'm here for further explanation
to my knowldege,You can open as many dialog as you want, only make sure that you gave them a unique widgetVar id:
<p:dialog widgetVar="dlg1">
<h:outputText value="Hello from first dialog"/>
</p:dialog>
<p:dialog widgetVar="dlg2">
<h:outputText value="Hello from second dialog"/>
</p:dialog>
...
<p:commandButton value="Open First" onclick="dlg1.show()"/>
<p:commandButton value="Open Second" onclick="dlg2.show()"/>
Clicking on the commandButton above will open two separate dialog parallelly.
I think your buttons made an update to the entire Naming Container that wraps your Dialog. If u do that, that's what you get.
You should update Container inside your Dialog that wraps your component inside.
Example :
Don't :
<h:panelGrid id="gridContainer">
<p:dialog id="dialogComponent>
// components
</p:dialog>
</h:panelGrid>
<p:commandButton update="#{p:component('gridContainer')}"/>
Do :
<h:panelGrid id="gridContainer">
<p:dialog id="dialogComponent>
<h:panelGrid id="insideContainer">
// components
</h:panelGrid>
</p:dialog>
</h:panelGrid>
<p:commandButton update="#{p:component('insideContainer')}"/>
I think you get the idea.
Hope it helps.
I use a dialog to show newsletters. The first time, everything goes ok: the dialog pops up and it can be closed using the X and using the extra button 'close'
<h:form id="frmDialog">
<p:dialog header="...: NEWS :..."
widgetVar="widgetInfo" modal="true" dynamic="true">
<p:commandButton value="close" onclick="widgetInfo.hide();"/>
<p:outputPanel id="pnlNewsLetter" style="width:610px;">
<ui:include src="#{corporateManager.newsLetter}"/>
</p:outputPanel>
</p:dialog>
</h:form>
....
When I click the button to reopen the same dialog, it opens, but can't be closed. In stead of closing, hitting the X button or the 'close' button, the entire content of the dialog gets selected and the page becomes inresponsive
.....
<h:form>
<h:commandButton image="/newsletters/img/1karel.png" onclick="widgetInfo.show();">
<f:ajax render=":frmDialog:pnlNewsLetter"/>
<f:setPropertyActionListener value="/newsletters/2012-12-21.html" target="#{corporateManager.newsLetter}"/>
</h:commandButton></h:form>
..... i've tried using p:commandButton, using oncomplete(), closable="false", used h:button, added/removed form-tags or id's etc...
Environment: Glasfish3.1.2 - Netbeans 7.3 - Primefaces 3.1 - Google Chrome 27.0.1453.94 m
Thanks to another post I've missed yesterday: dialog will not close primefaces ,
I've changed my code and it runs as expected, showing for each button another newsletter:
<p:commandButton oncomplete="widgetInfo.show();" value="" styleClass="karel4"
update=":pnlNewsLetter">
<f:setPropertyActionListener value="/newsletters/2013-03-19.html" target="#{corporateManager.newsLetter}"/>
</p:commandButton>
I had to remove <f:ajax render=":pnlNewsLetter"/> because otherwise the first newsletter was shown even when another button was clicked.
Many Thanks!