p:treeTable children root nodes duplicated after update - jsf

I'm getting a weird behavior when I try to update a h:panelGroup with a p:treeTable from a p:tree ajax event.
I have a p:tree element updating a form based on ui:include fragments. On the first load, everything works fine, but, when I select a tree, the ajax event is fired, the p:treeTable is updated but the nodes are duplicated.
My tree is this, the select listener event (onNodeSelect) builds a p:treeNode variable, and update a flag to show the p:treeTable page:
<p:tree value="#{mbArquitectura.raiz}" style="border: none;"
dynamic="true"
selectionMode="single"
cache="false"
selection="#{mbArquitectura.selectedNode}"
var="node"
id="tree">
<p:ajax onstart="muestraLoader(); cleanPriceTreeTable();"
oncomplete="ocultaLoader(); removeDuplicatedIds();"
event="select"
listener="#{mbArquitectura.onNodeSelect}"
global="true"
update=":frmPromocion :frmPromocion:ttPrecio :panelDialogos" />
<p:ajax onstart="muestraLoader();" oncomplete="ocultaLoader();"
event="expand"
listener="#{mbArquitectura.nodeExpand}"
global="true"
update=":frmPromocion :frmPromocion:ttPrecio :panelDialogos" />
<p:ajax onstart="muestraLoader();" oncomplete="ocultaLoader();"
event="collapse"
listener="#{mbArquitectura.nodeCollapse}"
global="true"
update=":frmPromocion :frmPromocion:ttPrecio :panelDialogos" />
<p:treeNode id="treeNode">
<b>
<h:outputText value="#{node}" id="lblNode" style="color: #{node.label}" />
</b>
</p:treeNode>
</p:tree>
My updated form (:frmPromocion) is this:
<ui:define name="content" id="content">
<h:form id="frmPromocion" style="font-size: x-small">
<h:panelGroup rendered="#{mbArquitectura.agregarPromocion}">
<ui:include src="/pages/ArqSeven/ArqPromocion.xhtml" />
</h:panelGroup>
<h:panelGroup rendered="#{mbArquitectura.precio}">
<ui:include src="/pages/ArqSeven/ArqPrecio.xhtml" />
</h:panelGroup>
</h:form>
Inside the file ArqPecio.xhtml, there is the following dataTable:
<p:treeTable id="ttPrecio"
liveResize="true"
value="${mbArquitectura.raizPrecio}"
var="item"
style="width: 1200px;"
styleClass="grid-content">
<p:ajax event="expand" listener="#{mbArquitectura.priceExpand}" update=":frmPromocion:ttPrecio" />
<p:ajax event="collapse" listener="#{mbArquitectura.priceCollapse}" update=":frmPromocion:ttPrecio" />
<p:ajax event="select" listener="#{mbArquitectura.priceSelect}" update=":frmPromocion:ttPrecio" />
<p:ajax event="unselect" listener="#{mbArquitectura.priceUnselect}" update=":frmPromocion:ttPrecio" />
</p:treetable>
As I said, the inicial load works fine:
But, when I select a node from the tree, the p:treeTable nodes are duplicated, like this:
How can I fix this behaviour?

Related

Right click on PrimeFaces tree node does not trigger select event

I am using a PrimeFaces 6.2 p:tree component with a context menu which differ for each node. When I click left and then right the menu is rendered properly, but when I click right directly the menu is not updated. Any ideas how to solve it?
I know that there are some posts about ajax after right click (event contextMenu), but it does not help, because the context menu disappears.
Sample p:tree can look like:
<p:tree id="docs" value="#{treeContextMenuView.root}" var="doc"
selectionMode="single"
selection="#{treeContextMenuView.selectedNode}" dynamic="true">
<p:ajax event="select" update="form:contextMenu" />
<p:treeNode expandedIcon="ui-icon-folder-open"
collapsedIcon="ui-icon-folder-collapsed">
<h:outputText value="#{doc.name}" />
</p:treeNode>
<p:treeNode type="document" icon="ui-icon-document">
<h:outputText value="#{doc.name}" />
</p:treeNode>
<p:treeNode type="picture" icon="ui-icon-image">
<h:outputText value="#{doc.name}" />
</p:treeNode>
<p:treeNode type="mp3" icon="ui-icon-video">
<h:outputText value="#{doc.name}" />
</p:treeNode>
</p:tree>
and sample p:contextMenu like:
<p:contextMenu for="docs" id="contextMenu">
<p:menuitem value="View" update="messages"
actionListener="#{treeContextMenuView.displaySelectedSingle}"
icon="ui-icon-search" />
<p:menuitem value="Item for Documents"
rendered="#{treeContextMenuView.selectedNode.data.name eq 'Documents'}"
icon="ui-icon-print" />
<p:menuitem value="Delete" update="docs"
actionListener="#{treeContextMenuView.deleteNode}"
icon="ui-icon-close" />
</p:contextMenu>
Full reproducible MVCE: https://github.com/szydra/primefaces-test
edit: Recently, I have found the same issue reported for p:dataTable:
issue on github.

Process primefaces menu before show

I have a primefaces menu which items are disabled on a condition from backing bean.
The problem is, that the conditions are processed after the update.
If I select a node which has every item enabled and switch to a node where everything is disabled,
the menu is reloaded but shows everything enabled for a second before the items are disabled.
Is there a way to process the disabled-conditions before the menu is shown?
<h:form id="form">
<p:tree id="tree" ...>
<p:ajax event="select" update=":form:tree:menu" listener...>
<p:treeNode id="treenode">
<p:commandButton id="btn" type="button" />
<p:overlayPanel for="btn">
<p:menu id=menu">
<p:menuitem .... disabled="#{bean.condition1}" />
<p:menuitem .... disabled="#{bean.condition2}" />
...
</p:menu>
</p:overlayPanel>
</p:treenode>
</p:tree>
EDITED
Hide the menu items at the beggining of the ajax call and show them when it is completed. The source code in the page would be:
<p:tree id="tree" value="#{bean.root}" var="node" selectionMode="checkbox">
<p:treeNode id="treenode">
<p:commandButton id="btn" value="#{node}"
onstart="$('.ui-overlaypanel-content').css('display','none');"
oncomplete="$('.ui-overlaypanel-content').css('display','block');"
actionListener="#{bean.processAndUpdateConditions}" update="mymenu"/>
<p:overlayPanel for="btn">
<p:menu id="mymenu" >
<p:menuitem value="Condition 1" disabled="#{bean.condition1}" />
<p:menuitem value="Condition 2" disabled="#{bean.condition2}" />
</p:menu>
</p:overlayPanel>
</p:treeNode>
</p:tree>

jsf required=true destroys setPropertyActionListener?

Using primefaces 4.0 and jsf 2.2.5
stmt.xhtml has 2 includes. IncludeDetail.xhtml and IncludeDuo.xhtml. IncludeDuo also includes IncludeDetail.
In IncludeDetail.xhtml the <ui:composition> Element owns no <form>, id-Attribute or any other special elements. Only <h:panelGrid>, <h:selectOneMenu> and <h:selectOneMenu>. Nothing special.
IncludeDuo.xhtml owns <p:layout> and <p:message> as child elements of <ui:composition>. Deeper inside the <p:layout> we find this piece of code:
<h:panelGrid columns="1" style="padding-left: 10px">
<h:outputText value="AS" />
<h:selectManyMenu value="#{regelBean.selectedASForNewElement}" required="true" style="height:115px">
<f:selectItems value="#{aSBean.elementList}" var="var" itemLabel="#{var.vaSl}"
itemValue="#{var.vaSl}" />
</h:selectManyMenu>
</h:panelGrid>
If I remove required="true" everything works as expected. If I leave it there, the following setPropertyActionListener won't do it's job anymore:
<h:form id="form1">
<p:dialog header="Neue Regel" widgetVar="newDuoDialog" resizable="false" id="newDuoDlg" showEffect="fade"
hideEffect="fade" modal="true" styleClass="newDialog" width="1220">
<ui:insert name="insertDuo">
<ui:include src="/includes/duoRegelStmt.xhtml" />
</ui:insert>
</p:dialog>
<p:growl id="msgs" showDetail="true" life="20000"/>
<div class="nvg-dataTable">
<p:dataTable id="dt1" var="tVar" value="#{stmtBean.elementList}"
scrollable="false" styleClass="nvg-mainTable" paginator="true"
paginatorAlwaysVisible="false" rows="10"
rowsPerPageTemplate="10,25,100" paginatorPosition="bottom"
currentPageReportTemplate="({startRecord}-{endRecord} von {totalRecords})"
emptyMessage="Keine Statements gefunden" filteredValue="#{stmtBean.filteredElements}">
<p:column styleClass="padding2" style="width:6%">
<p:commandButton value="?" update=":dlgForm"
oncomplete="PF('detDialog').show()" icon="" title="Detail">
<f:setPropertyActionListener value="#{tVar}" target="#{stmtBean.selectedElement}" />
</p:commandButton>
<p:commandButton value="N" update=""
oncomplete="PF('newDuoDialog').show()" icon="" title="Neue Regel mit diesem Statement als Grundlage">
<f:setPropertyActionListener value="#{tVar}" target="#{stmtBean.selectedElement}" />
</p:commandButton>
[ ... ]
Is this a bug or am I misusing sth?
This is expected behaviour: As you are setting the property on submit of the form the property is only set when the form is successfully submitted, which is not the case when validation fails i.e. a required field is empty.
Use process="#this" on the p:commandButton so the form is not submitted. This should work for you as you just want to open the dialog and set the property.

datatable selection is not updated when open dialog

i have an issue. I have one form and a dialog with another form inside. The second form has a datatable with radiobutton selection. When i open the dialog by first time, the selection is shown fine. I close the dialog. But when i try with another element, the selection on the datatable don't be updated.
The configuration that i use is:
Mojarra 2.2.4
Primefaces 4.0
But, if i use the Primefaces 3.5 version, it works.
I attach the xhtml files.
First file
<h:form id="formPlanificarCursos">
<p:outputPanel styleClass="pnlDeclaracionMessages">
<p:messages showSummary="true" />
</p:outputPanel>
<p:panel id="pnlPlanHorarioCurso" styleClass="pnlPlanHorarioCurso non-borders">
<components:titleSeparator title="Horarios de Curso" />
<!-- Toolbar -->
<p:outputPanel layout="block" styleClass="toolbar">
<p:commandLink id="btnAgregar" update="#(.dlgHorarioCurso)"
oncomplete="jQuery('.dlgHorarioCurso .ui-dialog-title').text('#{plan_msgs['planCurso.registrar.titulo']}'); dlgHorarioCurso.show();">
<h:graphicImage value="/resources/images/document_add.png" />
</p:commandLink>
<p:tooltip for="btnAgregar" value="Agregar Horario" />
</p:outputPanel>
<p:schedule id="scheduleCurso" minTime="6" value="#{detallePlanCursoBean.scheduleModel}" styleClass="scheduleCurso schedule-without-days"
allDaySlot="false" showHeader="false" view="agendaWeek" axisFormat="HH:mm" timeFormat="H:mm{ - H:mm}" aspectRatio="4" locale="es"
widgetVar="scheduleCurso">
<p:ajax event="eventSelect" listener="#{detallePlanCursoBean.onEventSelect}" update="#(.dlgHorarioCurso)"
oncomplete="jQuery('.dlgHorarioCurso .ui-dialog-title').text('#{plan_msgs['horarioCurso.modificar.titulo']}'); dlgHorarioCurso.show();" />
</p:schedule>
<f:facet name="footer">
<div class="div-botonera">
<p:commandButton id="btnAceptar" value="Aceptar" action="#{detallePlanCursoBean.registrarDetallePlanCurso}" />
<p:commandButton id="btnCancelar" value="Cancelar" action="#{detallePlanCursoBean.irConsultarPlanCurso}" immediate="true" />
</div>
</f:facet>
</p:panel>
</h:form>
<!-- Agregar Disponibilidad Horaria -->
<p:dialog widgetVar="dlgHorarioCurso" styleClass="dlgHorarioCurso" modal="true" resizable="false" closable="false">
<p:ajax event="close" listener="#{detallePlanCursoBean.cancelarHorarioCurso}" />
<ui:include src="/planificacion/horarioCurso.xhtml" />
</p:dialog>
Second file
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui" xmlns:o="http://omnifaces.org/ui"
xmlns:components="http://java.sun.com/jsf/composite/components">
<h:form id="frmHorarioCurso">
<p:panel styleClass="pnlHorarioCurso non-borders">
<p:messages id="messagesfrmHorarioCurso" />
<components:titleSeparator title="Aula" />
<p:outputPanel id="pnlAulas" styleClass="pnlAulas" style="border-width:0px;">
<p:dataTable emptyMessage="No hay aulas para seleccionar." var="aula" id="grdAulas" styleClass="grdAulas"
value="#{detallePlanCursoBean.aulaModel}" selection="#{detallePlanCursoBean.detallePlanCursoDTO.aula}" rows="3" paginator="true"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}"
currentPageReportTemplate="({currentPage} de {totalPages})" paginatorPosition="bottom" paginatorAlwaysVisible="false" widgetVar="grdAulas">
<p:column selectionMode="single" style="width:15px;" />
<p:column headerText="Nombre">
<h:outputText value="#{aula.nombre}" />
</p:column>
<p:column headerText="UbicaciĆ³n">
<h:outputText value="#{aula.locacion.nombre}" />
</p:column>
<p:column headerText="Capacidad" style="text-align:center;width:100px;">
<h:outputText value="#{aula.capacidad}" />
</p:column>
<p:column headerText="Accesibilidad" style="width:10%; text-align:center;">
<p:selectBooleanCheckbox value="#{aula.accesible}" disabled="true" />
</p:column>
</p:dataTable>
</p:outputPanel>
<f:facet name="footer">
<div class="div-botonera">
<p:commandButton value="Aceptar" action="#{detallePlanCursoBean.agregarHorarioCurso}" update="#(.pnlHorarioCurso)"
oncomplete="if(!args.validationFailed) HorarioCurso.handleComplete(xhr, status, args);" />
<p:commandButton value="Cancelar" oncomplete="scheduleCurso.update(); dlgHorarioCurso.hide();" update="#(.pnlHorarioCurso)" immediate="true"
action="#{detallePlanCursoBean.cancelarHorarioCurso}" />
</div>
</f:facet>
</p:panel>
</h:form>
I appreciate your help.
I was having a problem similar to this. I had a dialog which was being opened with information based on a pre-selected dataTable row, but the content of this dialog was not being updated after the first time it was opened.
I solved my problem by adding the attribute "process=#form" to my commandLink and in your case i think the update attribute should be update=":dlgHorarioCurso"

How to update component on clientside in primefaces?

I want to create add children button with dialog form feature.
On the page there are tree and modal dialog form. On every node of tree will be the create child button. If you click on create child button, there will be shown modal form, where parentId will be set as id of node where button was clicked
Tree:
<h:form id="TestGroupListForm">
<p:tree value="#{testTreeController.root}" var="node" dynamic="true" cache="false"
selectionMode="single" selection="#{treeBean.selectedNode}" id="tree">
<p:treeNode>
<h:outputText value="#{node.getName()}" /> <p:commandButton id="createButton#{node.getIdTestGroup()}" icon="ui-icon-plus" value="#{bundle.Create}" update="tree" oncomplete="TestGroupCreateDialog.show()"/>
</p:treeNode>
</p:tree>
</h:form>
Dialog Box:
<h:form id="TestGroupCreateForm">
<h:panelGroup id="display">
<p:panelGrid columns="2" >
<p:outputLabel value="#{bundle.CreateTestGroupLabel_name}" for="name" />
<p:inputText id="name" value="#{testGroupController.selected.name}" title="#{bundle.CreateTestGroupTitle_name}" />
<h:inputHidden id="parentId" value="#{testGroupController.selected.parentId}" />
</p:panelGrid>
<p:commandButton actionListener="#{testGroupController.saveNew}" value="#{bundle.Save}" update="display,:TestGroupListForm:tree,:growl" oncomplete="handleSubmit(xhr,status,args,TestGroupCreateDialog);"/>
<p:commandButton value="#{bundle.Cancel}" onclick="TestGroupCreateDialog.hide()"/>
</h:panelGroup>
</h:form>
</p:dialog>
I want that click on
<p:commandButton id="createButton#{node.getIdTestGroup()}" icon="ui-icon-plus" value="#{bundle.Create}" update="tree" oncomplete="TestGroupCreateDialog.show()"/>
Will set value of:
<h:inputHidden id="parentId" value="#{testGroupController.selected.parentId}" />
UPDATE
I have to use action listener testGroupController.nodeListener to set parentId of the new item.
<p:commandButton process="#this" id="createButton" actionListener="#{testGroupController.nodeListener}" icon="ui-icon-plus" value="#{bundle.CreateGroup}" update=":TestGroupCreateForm" oncomplete="TestGroupCreateDialog.show()">
<f:attribute name="rawParentId" value="#{node.getIdTestGroup()}" />
</p:commandButton>
You can add parentId to the existing update= attribute like so:
update="tree parentId"
This will render parentId and set its value to testGroupController.selected.parentId.
Edit
You can process any values from the UI to the been too, by using:
process="myInputId"
Example
<h:form>
<h:inputText id="input"
value="#{bean.value}" />
<h:outputText id="output"
value="#{bean.value}" />
<p:commandButton process="input"
update="output"
value="Submit" />
Upon clicking your button, the value of id="input" will be set in bean.value (as ordered by process="input"). Next your id="output" will be rendered (or updated) with bean.value (as ordered by update="output").

Resources