Different Context menu on each node of tree - jsf

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);

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.

p:treeTable children root nodes duplicated after update

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?

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>

primefaces using components in menuitem

I want to use other primefaces components in p:menuitem. Components display in page but actionlistener doesn't work and inputtext's value doesn't push to bean's value1 attribute. Is there any way to handle this problem?
<p:commandButton id="dynaButton" value="Search" type="button" icon="ui-icon-extlink"/>
<p:slideMenu overlay="true" trigger="dynaButton" my="left top" at="left bottom" style="width:180px">
<p:submenu label="Search">
<p:menuitem>
<p:outputLabel value="Search by Id" />
<p:inputText value="#{bean.value1}" />
<p:commandButton value="save" actionListener="#{bean.method1}" />
</p:menuitem>
</p:submenu>
<p:submenu label="Search By Product">
<p:menuitem value="Delete" ajax="false" icon="ui-icon-close"/>
</p:submenu>
<p:submenu label="Location" icon="ui-icon-extlink">
<p:submenu label="Prime Links">
<p:menuitem value="Prime" url="http://www.prime.com.tr" />
<p:menuitem value="PrimeFaces" url="http://www.primefaces.org" />
</p:submenu>
<p:menuitem value="Mobile" />
</p:submenu>
</p:slideMenu>
Try change your code to the following:
<p:menuitem>
<p:outputLabel value="Search by Id" />
<p:inputText id="inputField" value="#{bean.value1}" />
<p:commandButton process="inputField #this" value="save" actionListener="#{bean.method1}" />
</p:menuitem>
Check these answers too:
Why to add process=“#this” explicitly to p:commandButton to get action invoked?
Understanding process and update attributes of PrimeFaces
You miss the update attribute.
Note that menuitems can be directly processed, but cannot be directly updated, you need to update the entire menu
<p:slideMenu id="menu" ...>
<p:submenu label="Search">
<p:menuitem id="item">
<p:outputLabel value="Search by Id" />
<p:inputText value="#{bean.value1}" />
<p:commandButton value="save" actionListener="#{bean.method1}" process="item" update="menu" />
<h:outputText value="#{bean.value1}" />
</p:menuitem>
</p:submenu>
</p:slideMenu>

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