I'm using PF 3.5 and JSF Mojarra 2.1.
I have a dialog which I want to use appendToBody=true. This usually results in "unpredictable behavior" though.
Basically what the dialog does is, when I choose an entry (a persn entity) from a datatable, it gives me filled up input boxes which I can edit, thus editing the particular entry (person details).
Sometimes the input boxes get filled up properly with the entries data. Sometimes they dont.
This behavior does not happen with appendToBody=false.
Aside from that I'm pretty sure there are no nested forms.
As you will notice I am trying out a "One page design" with purely ajax navigation.
Main page (index.xhtml)
<h:body>
<pe:layout id="page" fullPage="true">
<!-- North -->
<pe:layoutPane id="north" position="north" minSize="140"
closable="true" resizable="false">
....
</pe:layoutPane>
<!-- West -->
<pe:layoutPane id="west" position="west" minWidth="150" size="180"
style="font-size: 14px !important;" closable="true"
styleClassHeader="menuBar" resizable="false">
<f:facet name="header">Main Menu</f:facet>
<h:form id="form1">
<p:panelMenu id="panelMenu" style="width: 160px !important">
<!-- On menu click update with Ajax centerpanel and msgPanel -->
<p:submenu label="Persons" style="font-size: 10px ">
<p:menuitem value="Person List" update=":centerpanel"
actionListener="#{layout.setAll('formPersonList.xhtml', 'Person List')}"
action="#{person.init()}">
</p:menuitem>
</p:submenu>
.....
</p:panelMenu>
</h:form>
</pe:layoutPane>
<!-- Center -->
<pe:layoutPane id="content" position="center"
style="font-size: 14px !important" styleClassHeader="menuBar">
<h:panelGroup id="centerpanel" layout="block">
<ui:include id="include" src="#{layout.navigation}" />
</h:panelGroup>
</pe:layoutPane>
</pe:layout>
The dialog is in a file formPersonList.xhtml and is outside the form
<ui:composition ....>
<h:form id="mainForm">
<p:contextMenu for="personTable">
<p:menuitem value="View Details"
process="#form" actionListener="#{person.handleSelectedPerson()}"
update=":dlgPersonGrp"
oncomplete="dlgPerson.show();">
</p:menuitem>
</p:contextMenu>
<p:dataTable id="personTable ....>
....person entities
</p:dataTable>
</h:form>
<p:dialog widgetVar="dlgPerson" showEffect="size"
width="1100" appendToBody="true">
<h:panelGroup id="dlgPersonGrp">
<ui:include src="formPerson.xhtml" />
</h:panelGroup>
</p:dialog>
</ui:composition>
Finally, the form with the input boxes: formPerson.xhtml
<ui:composition ....>
<h:form id ="subForm">
....Input boxes that are supposed to be filled up from a backing bean
and then resubmitted to edit the chosen entry
</h:form>
</ui:composition>
I have tried to dumb it down as much as possible. Let me know if you need more detail.
I know this is a old question, but I was having the same problem with Primefaces 5.
The solution was simple, I've included the attribute appendTo="#(body)" in tag.
<p:dialog header="Title" widgetVar="dlg" modal="true" appendTo="#(body)">
<h:outputText value="Dialog text..." />
<p:commandButton value="Ok" onclick="PF('dlg').close()" />
</p:dialog>
Perhaps the answer is not to use appendToBody. Do you really need it?
One of the common reasons for using appendToBody is to avoid error resulting from putting modal dialogs inside layouts. This workaround, as you've already noted, results in "unpredictable behaviour".
The better way would be just to place the dialog outside the layout.
For more details please see:
http://forum.primefaces.org/viewtopic.php?f=3&t=6154
http://forum.primefaces.org/viewtopic.php?f=3&t=16504
Having the following xhtml code:
<h:form id="COTreeForm">
<p:tree value="#{COBean.root}" var="node" id="COTree" dynamic="true" selectionMode="single">
<p:ajax event="select" update="#(.coDetailsPanel)" listener="#{COBean.onNodeSelect}" />
<p:treeNode id="COtreeNode" type="customerOrder" icon="ui-icon-co">
<p:outputPanel id="CO_#{node.key}"> CO: #{node.key} </p:outputPanel>
<!-- <p:draggable for="CO_#{node.key}" helper="clone" /> -->
</p:treeNode>
<p:treeNode id="COItreeNode" type="customerOrderItem">
<p:outputPanel id="COI_#{node.key}" styleClass="ui-tree-node-label-coi"> COI: #{node.key} </p:outputPanel>
<!-- <p:draggable for="COI_#{node.key}" helper="clone" /> -->
</p:treeNode>
</p:tree>
</h:form>
The <p:outputPanel id="CO_#{node.key}"> CO: #{node.key} </p:outputPanel> is evaluated to the following HTML code:
<span id="COTreeForm:COTree:0:CO_"> CO: customer1_co1 </span>
Why #{node.key} is evaluated to an empty string for the id attribute?! Please notice that it's evaluated correctly as the tag content.
The id (and binding) attributes are evaluated during view build time. The #{node} is however only available during view render time. For a more detailed explanation, read JSTL in JSF2 Facelets... makes sense?
Just don't use _#{node.key} at all in all your id and for attributes. JSF/PrimeFaces will already autogenerate the right unique client IDs depending on the currently iterated tree node.
I've created an ui:component to use like a popup, so I can create a lot of popups using the standard of this template.
The component is just a popup with two buttons (cancel and submit) and a content that can be overriden, like you can see here:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.prime.com.tr/ui">
<ui:component>
<p:dialog widgetVar="#{idPopup}" id="#{idPopup}" modal="#{popup.modal}"
draggable="#{popup.modal}"
rendered="#{popup.visivel}" visible="#{popup.visivel}"
closeOnEscape="false" closable="false" header="#{titulo}"
resizable="false" styleClass="autoWidthDialog" showEffect="fade"
hideEffect="fade">
<h:panelGroup style="width:100%">
<p:focus />
<ui:insert name="conteudo">Nenhum conteúdo definido!</ui:insert>
<h:panelGrid id="#{idPopup}PainelMensagens" style="width:100%">
<p:messages />
</h:panelGrid>
<ui:insert name="barraDeBotoes">
<h:panelGroup layout="block" style="width:100%">
<p:commandButton value="CANCELAR" immediate="true" update="#form"
style="float:right" action="#{controladorPopup.fechar}"
onclick="#{idPopup}.hide();" />
<p:commandButton value="OK" style="float:right"
update="#form formAlerta"
action="#{controladorPopup.submit}"
process="#form" />
</h:panelGroup>
</ui:insert>
</h:panelGroup>
</p:dialog>
</ui:component>
</html>
The problem happen when I try to submit the form without filling the required fields. The correct behavior is just show again the popup with messages, but the dialog is rendered twice, one with the messages and one without the messages.
You can see this behavior here:
this is one use of this template:
<ui:composition template="../templates/popupSubmit.xhtml">
<ui:param name="titulo" value="Buscar pessoa" />
<ui:param name="popup" value="#{modeloPopupBuscaPessoa}" />
<ui:param name="controladorPopup"
value="#{controladorPopupBuscaPessoa}" />
<ui:define name="conteudo">
<h:panelGroup>
<h:panelGrid columns="2">
<h:outputLabel value="Tipo de cadastro:" style="float:none" />
<h:selectOneMenu value="#{controladorSugestaoPessoa.tipoCadastro}"
immediate="true">
<f:selectItems value="#{carregadorTipoCadastro.itens}" />
<f:ajax event="change" immediate="true" />
</h:selectOneMenu>
</h:panelGrid>
<h:outputText value="Buscar por:" />
<h:selectOneRadio value="#{controladorSugestaoPessoa.tipoBusca}"
immediate="true">
<f:selectItems value="#{carregadorTipoBuscaPessoa.itens}" />
<f:ajax event="change" immediate="true" />
</h:selectOneRadio>
<p:autoComplete value="#{modeloPopupBuscaPessoa.itemSelecionado}"
forceSelection="true" maxResults="10" queryDelay="500"
completeMethod="#{controladorSugestaoPessoa.atualizarSugestoes}"
var="pessoa" itemLabel="#{pessoa.label}" itemValue="#{pessoa}"
converter="#{conversorSelectItem}" />
</h:panelGroup>
</ui:define>
</ui:composition>
And these are some use:
<h:form id="cadastroPessoa">
<ui:include
src="resources/components/popups/modulo_cadastro/popupNovoCadastroPessoa.xhtml">
<ui:param name="idPopup" value="popupNovoCadastroPessoa" />
</ui:include>
<ui:include
src="resources/components/popups/modulo_cadastro/popupCadastroPessoa.xhtml">
<ui:param name="idPopup" value="popupEdicaoCadastroPessoa" />
</ui:include>
<ui:include
src="resources/components/popups/modulo_cadastro/popupBuscaPessoa.xhtml">
<ui:param name="idPopup" value="popupBuscaCadastroPessoa" />
</ui:include>
</h:form>
<h:form id="cadastroProduto">
<ui:include
src="resources/components/popups/modulo_cadastro/popupCadastroProduto.xhtml">
<ui:param name="idPopup" value="popupNovoCadastroProduto" />
</ui:include>
</h:form>
Could someone tell me why this is happening??
I've posted the same question in primefaces forum (like Tommy Chan told), and someone answered this:
You are probably placing your dialog in the form you are updating which is a nono. Never update the dialog only the stuff in the dialog
I've tried to do this until I saw all my dialogs have "rendered" attribute coming from server (just see the first xml), I have a lot of dialogs in this application and some of them have relation with others (on server), these last are on the same form.
I did something different, I only created this javascript code:
function removerDialogo(id) {
setTimeout(function() {
removerDialogoAposIntervalo(id);
}, 100);
}
function removerDialogoAposIntervalo(id) {
id = id.replace(':', '\\:');
jQuery('div.ui-dialog')
.find('#' + id)
.parent().eq(1)
.remove();
}
and called this on dialog "onShow" attribute:
<p:dialog widgetVar="#{idPopup}" id="#{idPopup}" modal="#{popup.modal}"
draggable="#{popup.modal}" rendered="#{popup.visivel}"
visible="#{popup.visivel}" closeOnEscape="false" closable="false"
header="#{titulo}" resizable="false" styleClass="autoWidthDialog"
showEffect="fade" hideEffect="fade" onShow="removerDialogo(this.id)">
I don't like to do things like this, but I can't find a better way to solve this...
If someone give me a better solution, I will be grateful
In my case I cannot user oncompleteI) method to hide the dialog because it has to be closed to some business logic.
I my case I have use primefaces tabs on UI. Every time I navigate the tabs and then click on button on which dialog appears then my dialogs number are increasing proportionality
So I have used simple jquery script to remove all the duplication dialog from the UI
e UI.
function removeDuplicateDialogs(dialogId) {
\\ generally all our components have : character we have to
\\ replace ':' with '\\:'(applying escape character)
dialogId = dialogId.replace(/\:/g, '\\:');
var dialogs = jQuery("div[id=" + dialogId + "]");
var numOfDialogs = dialogs.length;
numOfDialogs = numOfDialogs - 1;
for (var i = 0; i < numOfDialogs; i++) {
jQuery(dialogs[i]).remove();
}
}
As i said on the primefaces forum, you are updating your forms with the dialog in it... you need to place your dialogs out of your form and update them seperatly. If you need to use a form in your dialog then place it in you dialog:
<p:dialog><p:form> </p:form> </p:dialog>
I had the same problem with a dialog, the solution was place in the update of the commandButton that show the dialog component the specific id of the Dialog Component not the form id, the solution looks like this:
<p:dialog id="dialogId">
<p:commandButton value="OK" style="float:right"
update="#form dialogId"
action="#{controladorPopup.submit}"
process="#form"/>
</p:dialog>
I would check that your widgetVar="#{idPopup}" id="#{idPopup}" is the same before you submit and after you submit the form. Maybe it has changed and primefaces thinks it doesn't exist anymore and creates a new one.
Add the oncomplete attribute to your submit button and let it hide the dialog:
<p:commandButton value="OK" style="float:right"
update="#form formAlerta"
action="#{controladorPopup.submit}"
process="#form"
oncomplete="#{idPopup}.hide();"/>
putting the forms inside dialog isnt the best way to solve it, if you access your application with IExplorer, dialogs wont work with this approach
This is an awful bug with no official answer...
I'm using a dialog to render a Google map. The way I handle the bug (using JQuery) is by counting the number of ".map" elements in the DOM on primefaces:dialog.onShow... I then select the :last .map instance rendered (or in your case, whatever content class you're working with), and .remove() the dialog which contains it:
Markup (approx):
<pri:dialog onShow="popupOpen();" etc...>
<div id="map" class"map"></div>
</pri:dialog>
JavaScript:
function onShowDialog(){
if($(".map").length > 1){
$cull = $(".map:last");
$cull.closest(".ui-dialog").remove();
}
}
If you're a sadist you could, quite comfortably, make that a one liner... I see this as a Primefaces bug. The close button should outright destroy the dialog.
i have page with menu in left side and content in the right
every commandLink in left menu change the snippet of the content and activate function that update the current user details (every ):
in profile.xhtml :
in ui:composition tag.
<ui:define name="menuLeft">
<div id="Div2" style="width:172px; padding: 0; font-size: 10px; float:left">
<ui:include src="/users/sections/profile/profileleft.xhtml"/>
</div>
</ui:define>
<ui:define name="content">
<div id="Div3" style="background-color:white; width: 708px; height:1208px; padding: 0; font-size: 12px; float:left">
<ui:include src="/users/sections/profile/content.xhtml"/>
</div>
</ui:define>
<ui:define name="menuRight"/>
in content.xhtml:
in ui:composition tag.
<h:panelGroup id="profileContentSnippet" >
<ui:include src="#{snippetsProfileLinkerBean.snippetFileName}"/>
</h:panelGroup>
in profileleft.xhtml
in ui:composition tag.
<ui:include src="/users/source/profile/leftMenu/menu.xhtml"/>
in menu.xhtml:
in ui:composition tag.
<h:commandLink value="ViewProfilePersonalDetails" action="#{usersController.prepareConnected}">
<f:param name="pageViewId" value="ViewProfilePersonalDetails"/>
<f:ajax render="main:profileContentSnippet" />
</h:commandLink>
in editPersonalDetails-snippet.xhtml:
in ui:composition tag.
<h:outputText value="#{bundle.ViewUsersLabel_userID}"/>
<h:outputText value="#{usersController.selected.userID}" title="# {bundle.ViewUsersTitle_userID}"/>
<h:commandLink action="#{usersController.prepareProfileConnected}" value="view" actionListener="#{snippetsProfileLinkerBean.action}">
<f:attribute name="pageToViewId" value="ViewProfilePersonalDetails" />
<f:ajax render="main:profileContentSnippet" />
in viewPersonalDetails-snippet.xhtml:
in ui:composition tag.
<h:commandLink action="#{usersController.prepareProfileConnected}" value="edit" actionListener="#{snippetsProfileLinkerBean.action}">
<f:attribute name="pageToViewId" value="EditProfilePersonalDetails" />
<f:ajax render="main:profileContentSnippet" />
<h:outputText value="#{bundle.ViewUsersLabel_userID}"/>
<h:outputText value="#{usersController.selected.userID}" title="#{bundle.ViewUsersTitle_userID}"/>
</h:commandLink>
the usersController is request bean that have prepareProfileConnected function that update her selected fild with user details from DB.
the snippetsProfileLinkerBean is request bean that have two options for getting the snippet file name : by f:param or by using action(ActionEvent event) function.
when i click in the left menu everything is working i get the snippet and i see the user ID.
THE BIG PROBLEM IS when i click the edit or the view in the snippet files that also need
to activate function to get user details and change snippet, in some cases the
h:commandLink in the snippets dont work at all.
HOW can I activate h:commandLink in snippet - that will change the snippet file and also
call the function in usersController to update user details?
Inside one tab, I can cilck on a button to display an "h:groupPanel". If I do this, and then change the active tab, the groupPanel that has just appeared is still visible, and appears on top of the now current tab.
The code for the tabView is:
<p:tabView dynamic="true" cache="false" id="characterTabView">
<p:tab title="View" id="viewTab">
<ui:include src="/sections/character/view.xhtml" />
</p:tab>
<p:tab title="Upgrade" id="upgradeTab">
<ui:include src="/sections/character/upgrade.xhtml" />
</p:tab>
</p:tabView>
The "upgrade" page looks like
<h:panelGroup id="searchCompetencies" rendered="#{characterBean.rightPanel == 'searchResult'}">
<h:panelGroup styleClass="characterUpgradeLeft">
<ui:include src="/sections/character/searchViewLeft.xhtml" />
</h:panelGroup>
<h:panelGroup id="competencyCreation" rendered="#{characterBean.rightPanel == 'competencyCreation'}">
<!-- The panel that is made visible -->
</h:panelGroup>
And the page in which the component is made visible (searchViewLeft):
<p:fieldset legend="Create competency" styleClass="createCompetencyStart">
<h:form>
<p:commandButton value="Create competency" type="button" onclick="toggleCreate()" update="upgradeTab" />
</h:form>
</p:fieldset>
where "toggleCreate" changes the value of "characterBean.rightPanel".
Would you have any idea as to what I am missing here?
Thanks a lot :)