Implement Dynamic ContextMenu for a Multipage Primefaces Datatable File

I have a paged PrimeFaces Datatable with a context menu, and I want to implement multi-selection, where the menu items in the context menu will depend on the number of items selected, as some actions will be available only if only one item is selected, while others will be valid when selecting one or more.

My first idea was to use the “visualized” version of the individual menu items that is installed in the bean controller. Work such as the correct menu items were displayed. The problem is that using the visualized functionality of the menu items led to the fact that the selection was lost on the basis of data, which deprives the goal of the exercise.

<p:dataTable id="orders" dynamic="true" var="item" rowKey="#{item.id}" value="#{ordersController.orders}" emptyMessage="#{uistrings['datatable.nodata']}" paginator="true" paginatorPosition="both" paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}" paginatorAlwaysVisible="false" rows="10" selectionMode="multiple" selection="#{ordersController.selectedOrders}" widgetVar="orderList"> <p:ajax event="sort" listener="#{ordersController.onSort}" update="orders"/> <p:ajax event="rowSelect" update="contextMenu"/> <p:ajax event="rowUnselect" update="contextMenu"/> <p:column id="balance_date" sortBy="#{item.balanceDate}"> <f:facet name="header"> <h:outputText value="#{uistrings['orders.column.label.balancedate']}"/> </f:facet> <h:outputText value="#{item.balanceDate}"> <f:converter converterId="isoDateTimeConverter"/> <f:attribute name="#{webUiConstBean.ISO_CONVERTER_ATTRIBUTE_TYPE}" value="#{webUiConstBean.ISO_DATE_CLASS}" /> <f:attribute name="#{webUiConstBean.ISO_CONVERTER_ATTRIBUTE_PATTERN}" value="#{webUiConstBean.ISO_DATE_FORMAT}" /> </h:outputText> </p:column> <p:column id="recipient_name" sortBy="#{item.recipient.displayName}"> <f:facet name="header"> <h:outputText value="#{uistrings['orders.column.label.recipient.displayName']}"/> </f:facet> <h:outputText value="#{item.recipient.displayName}"/> </p:column> [snip] </p:dataTable> <p:contextMenu id="contextMenu" for="orders"> <p:menuitem value="#{uistrings['orders.menu.details']}" update="details, orders" oncomplete="detailDialog.show()" icon="ui-icon-search" rendered="#{ordersController.renderDisplayDetails}" /> <p:menuitem value="#{uistrings['orders.button.label.delete']}" icon="ui-icon-trash" update="orders" ajax="true" onclick="confirmDelete.show()" rendered="#{ordersController.renderDeleteDocuments}"/> </p:contextMenu> 

After finding solutions in this and other forums, finding some tips and finding out several alternatives, I made several other attempts, including:

1) using two full context menus: one when one element is selected, and the other when many elements are selected, and using the rendered parameter in the context menus themselves, and not on their elements.

In this case, the rowSelect and rowUnselect events are updated as

  <p:ajax event="rowSelect" update="contextMenu1Selected contextMenuManySelected"/> <p:ajax event="rowUnselect" update="contextMenu1Selected contextMenuManySelected"/> 

And the context menus look something like this.

  <p:contextMenu id="contextMenu1Selected" for="orders" rendered="#{ordersController.render1Selected}"> <p:menuitem value="#{uistrings['orders.menu.details']}" update="details, orders" oncomplete="detailDialog.show()" icon="ui-icon-search"/> <p:menuitem value="#{uistrings['orders.button.label.delete']}" icon="ui-icon-trash" update="orders" ajax="true" onclick="confirmDelete.show()"/> </p:contextMenu> <p:contextMenu id="contextMenuManySelected" for="orders" rendered="#{ordersController.renderManySelected}"> <p:menuitem value="#{uistrings['orders.button.label.delete']}" icon="ui-icon-trash" update="orders" ajax="true" onclick="confirmDelete.show()"/> </p:contextMenu> 

But that didn't work at all. No menus were shown.

2) Placing two context menus inside the OutputPanel and updating the panel. This had the same result as my first attempt. that is, menu items are displayed correctly, but lose their selection

  <p:outputPanel id="contextMenuPanel" autoUpdate="true"> <p:contextMenu id="contextMenu1Selected" for="orders" rendered="#{ordersController.renderDisplayDocument}"> [menu items] </p:contextMenu> <p:contextMenu id="contextMenuManySelected" for="orders" rendered="#{ordersController.renderDeleteDocuments}"> [menu items] </p:contextMenu> </p:outputPanel> 

3) Definition of the contextMenu model using the Model menu provided by the controller, which itself has two models available for these two cases, and provides the correct option depending on the number of selected elements. Also in the output panel

  <p:outputPanel id="contextMenuPanel" autoUpdate="true"> <p:contextMenu id="contextMenu" for="orders" model="#{ordersController.menuModel}"/> </p:outputPanel>> 

That didn't work either. MenuItems are correctly displayed, but multi-position fragments are lost as before.

I have exhausted the options that I know of.

Has anyone successfully implemented dynamic context menus for datatables with multi-select?

Or does anyone have other ideas that might work?

Greetings.

+6
source share
1 answer

Maybe too late, but here is my solution ...

Context menu with javascript:

 <p:contextMenu id="searchResultTableContextMenuId" for="searchResultTableId" beforeShow="return true;" widgetVar="searchResultTableContextMenuVar"> <p:menuitem value="#{msgs['label.resultlistAction.edit']}" disabled="#{curSelectedDocsCount ne 1}" icon="fa fa-pencil" oncomplete="PF('editPropertyDialogVar').show();" update=":editPropertyFormId" /> <p:menuitem value="#{msgs['label.resultlistAction.delete']}" disabled="#{curSelectedDocsCount le 0}" icon="fa fa-trash" actionListener="#{deleteDocumentBL.initFromResultList()}" oncomplete="PF('deleteDocumentsDialogVar').show();" update=":deleteDocumentsFormId" /> <p:menuitem value="#{msgs['label.resultlistAction.download']}" disabled="#{curSelectedDocsCount ne 1}" icon="fa fa-download" ajax="false" action="#{contentBL.downloadMainContent(curSearch.getViewId(), curSearch.selectedSearchResults.get(0))}" /> <p:menuitem value="#{msgs['label.resultlistAction.clearSelectionId']}" disabled="#{curSelectedDocsCount lt 1}" icon="fa fa-times-circle-o" action="#{curSearch.clearSelectedSearchResults()}" update="@(.resultlistActionGrid) @(.searchResultTable)" oncomplete="PF('hitlistTableVar').unselectAllRows();" /> </p:contextMenu> <!-- javascript to fix problem that the context menu hides if it is updated in ajax event contextMenu --> <script type="text/javascript"> var currentEvent; $(document).ready(function () { PrimeFaces.widget.ContextMenu.prototype.show = function (e) { // hide other contextmenus if any $(document.body).children('.ui-contextmenu:visible').hide(); if (e) { currentEvent = e; } var win = $(window), left = e.pageX, top = e.pageY, width = this.jq.outerWidth(), height = this.jq.outerHeight(); //collision detection for window boundaries if ((left + width) > (win.width()) + win.scrollLeft()) { left = left - width; } if ((top + height ) > (win.height() + win.scrollTop())) { top = top - height; } if (this.cfg.beforeShow) { this.cfg.beforeShow.call(this); } this.jq.css({ 'left': left, 'top': top, 'z-index': ++PrimeFaces.zindex }).show(); e.preventDefault(); }; }); </script> 

The DataTable must handle some ajax events to display and update the context menu:

 <p:dataTable id="searchResultTableId" ...> <p:ajax event="rowSelect" update=":searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId" /> <p:ajax event="rowUnselect" update=":searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId" /> <p:ajax event="toggleSelect" update=":searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId" /> <p:ajax event="rowSelectCheckbox" update=":searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId" /> <p:ajax event="rowUnselectCheckbox" update=":searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId" /> <p:ajax event="contextMenu" update=":searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId" oncomplete="PF('searchResultTableContextMenuVar').show(currentEvent);" /> </p:dataTable> 
+2
source

All Articles