Process primefaces menu before show - jsf

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>

Related

How stop row selecting in primefaces tree after button is clicked

I have primefaces tree with button and outputtext in treenode. Ajax row select event calls rendering of button. The button has primefaces tired menu which has to appear when button is clicked. The problem is that the button click calls the row select event and the button is rerendered and the menu dissapeared.
<p:tree id="tree1" value="#{treeDNDView.root1}" var="node" selectionMode="single"
selection="#{treeDNDView.selectedNode1}">
<p:ajax event="select" update=" mainform:tree1"/>
<p:treeNode>
<h:panelGrid columns="3" columnClasses="width-5pct,verticalLine,width-95pct">
<p:outputPanel>
<p:commandButton id="dynaButton" value="Show" rendered="#{treeDNDView.selectedNode1.data eq node}" type="button"/>
<p:tieredMenu id="treeNodePanel" overlay="true" trigger="dynaButton" my="left top" at="left bottom">
<p:menuitem value="Save" action="#{menuView.save}"/>
</p:tieredMenu>
</p:outputPanel>
<p:spacer width="5px"/>
<p:outputPanel>
<h:outputText value="#{node}" escape="false"/>
</p:outputPanel>
</h:panelGrid>
</p:treeNode>
</p:tree>
How to separate button click and row select events in this case? How rewrite code to make functionaliry succesfull working?
The problem will be solved by adding the .stopPropagation() to on click event.
<p:outputPanel>
<div onclick="(function(e) { e.preventDefault(); e.stopPropagation(); })(event)">
<p:commandButton id="dynaButton" value="Show" rendered="#{treeDNDView.selectedNode1.data eq node}" type="button"/>
<p:tieredMenu id="treeNodePanel" overlay="true" trigger="dynaButton" my="left top" at="left bottom">
<p:menuitem value="Save" action="#{menuView.save}"/>
</p:tieredMenu>
</div>
</p:outputPanel>

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.

p:splitButton menu item to launch a p:dialog

I am trying to have a p:splitButton p:menuItem launch a p:dialog. I have the following
<h:form>
<p:splitButton value="Action" icon="ui-icon-circle-triangle-s">
<p:menuitem value="New label" icon="ui-icon-newwin">
<p:commandLink onclick="PF('dlg1').show();"/>
</p:menuitem>
</p:splitButton>
<p:dialog header="Modal Dialog" widgetVar="dlg1" modal="true" height="100">
<h:outputText value="This is a Modal Dialog." />
</p:dialog>
</h:form>
I can't however see the "New label" menu item in the list. Is what I'm trying to achieve possible?
Managed to fix it like so
<h:form>
<p:splitButton value="Action" icon="ui-icon-circle-triangle-s">
<p:menuitem value="New label" icon="ui-icon-newwin" onclick="PF('dlg1').show();" />
</p:splitButton>
<p:dialog header="Modal Dialog" widgetVar="dlg1" modal="true" height="100">
<h:outputText value="This is a Modal Dialog." />
</p:dialog>
</h:form>

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").

Different Context menu on each node of tree

In my JSF project I want to display different context menu on every node of tree based on some conditions (To be precise some permissions)
Present according to my xhtml, I have binded context menu with the tree so I am getting same menu on every node of the tree.
Here is the code:
<p:contextMenu for="TreeID">
<p:menuitem value="Create" update=":centerPanel" actionListener="#{someBean.createPrivilege}" onstart="statusDialog.show();"
oncomplete="statusDialog.hide();" />
<p:menuitem value="Edit" update=":commonDialog :centerPanel" actionListener="#{someBean.editPrivilege}"
onstart="statusDialog.show();" oncomplete="statusDialog.hide();" />
<p:menuitem value="Delete" onstart="delPrivilegeConfirmDialog.show();" />
</p:contextMenu>
<p:scrollPanel mode="native" styleClass="scroll-panel">
<p:tree id="TreeID" value="root" var="node" selectionMode="single"
selection="#{someBean.selectedNode}" dynamic="true">
<p:ajax listener="#{someBean.onNodeSelect}" update=":centerPanel" event="select" onstart="statusDialog.show();"
oncomplete="statusDialog.hide();" />
<p:treeNode id="someID">
<h:outputText value="#{node}" id="lblNode" />
</p:treeNode>
</p:tree>
</p:scrollPanel>
But according to my requirement I want different context menu on every node, basically I have 3 options in my context menu like Create, Edit , Delete.. then I need to hide 1 or 2 option on every node based on certain conditions.
How would I do that?
Thanks in advance.
Assuming that you are using PrimeFaces, recent versions provide the option to set different context menus for different node types using the "nodeType" attribute:
<p:contextMenu for="TreeID" nodeType="type1">
<p:menuitem value="Create" update=":centerPanel" actionListener="#{someBean.createPrivilege}" onstart="statusDialog.show();"
oncomplete="statusDialog.hide();" />
<p:menuitem value="Edit" update=":commonDialog :centerPanel" actionListener="#{someBean.editPrivilege}"
onstart="statusDialog.show();" oncomplete="statusDialog.hide();" />
<p:menuitem value="Delete" onstart="delPrivilegeConfirmDialog.show();" />
</p:contextMenu>
<p:contextMenu for="TreeID" nodeType="type2">
<!-- Other menu items -->
</p:contextMenu>
<p:scrollPanel mode="native" styleClass="scroll-panel">
<p:tree id="TreeID" value="root" var="node" selectionMode="single"
selection="#{someBean.selectedNode}" dynamic="true">
<p:ajax listener="#{someBean.onNodeSelect}" update=":centerPanel" event="select" onstart="statusDialog.show();"
oncomplete="statusDialog.hide();" />
<p:treeNode id="someID" type="type1">
<h:outputText value="#{node}" id="lblNode" />
</p:treeNode>
<p:treeNode id="someID" type="type2">
<h:outputText value="#{node}" id="lblNode" />
</p:treeNode>
</p:tree>
</p:scrollPanel>
Just keep in mind that you need to set the node type for all nodes generated by the model:
TreeNode x = new DefaultTreeNode("type1", data, parent);

Resources