Primefaces多选Datatable实现动态Context

Primefaces多选Datatable实现动态Context

本文介绍了为Primefaces多选Datatable实现动态ContextMenu的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有上下文菜单的分页的PrimeFaces Datatable,我希望实现多选择,其中上下文菜单中的菜单项将取决于所选项目的数量,因为一些操作只有在只有一个选择项目,其他选项将有效。



我的第一个想法是使用个别菜单项的呈现选项,该选项设置在控制器bean。这样的作品,确实显示正确的菜单项目。问题是,使用menuitems的渲染功能会影响到datatable上的选择丢失,从而击败了练习的目的。

 < p:dataTable id =ordersdynamic =truevar =itemrowKey =#{item =#{ordersController.orders}
emptyMessage =#{uistrings ['datatable.nodata']}paginator =truepaginatorPosition =both
paginatorTemplate = {CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}
paginatorAlwaysVisible =falserows =10selectionMode =multipleselection =#{ordersController.selectedOrders}widgetVar = orderList>

< p:ajax event =sortlistener =#{ordersController.onSort}update =orders/>
< p:ajax event =rowSelectupdate =contextMenu/>
< p:ajax event =rowUnselectupdate =contextMenu/>

< p:column id =balance_datesortBy =#{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_namesortBy =#{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 =contextMenufor =orders>
< p:menuitem value =#{uistrings ['orders.menu.details']}update =详细信息,订单
oncomplete =detailDialog.show()icon =ui -icon-searchrendered =#{ordersController.renderDisplayDetails}/>

< p:menuitem value =#{uistrings ['orders.button.label.delete']}icon =ui-icon-trash
update =orders ajax =trueonclick =confirmationDelete.show()
rendered =#{ordersController.renderDeleteDocuments}/>
< / p:contextMenu>

在这个和其他论坛中寻找解决方案后,找到一些提示,并自己选择一些替代方法我进行了一些尝试,其中包括:



1)使用两个完整的上下文菜单:一个用于当选择一个项目时,另一个用于当选择了多个项目时,以及使用在上下文菜单本身而不是他们的项目中渲染的选项。



在这种情况下,rowSelect和rowUnselect事件更新

 < p:ajax event =rowSelectupdate =contextMenu1Selected contextMenuManySelected/> 
< p:ajax event =rowUnselectupdate =contextMenu1Selected contextMenuManySelected/>

上下文菜单看起来像这样

 < p:contextMenu id =contextMenu1Selectedfor =ordersrendered =#{ordersController.render1Selected}> 
< p:menuitem value =#{uistrings ['orders.menu.details']}update =详细信息,订单
oncomplete =detailDialog.show()icon =ui -icon-search/>

< p:menuitem value =#{uistrings ['orders.button.label.delete']}icon =ui-icon-trash
update =orders ajax =trueonclick =confirmDelete.show()/>
< / p:contextMenu>

< p:contextMenu id =contextMenuManySelectedfor =ordersrendered =#{ordersController.renderManySelected}>
< p:menuitem value =#{uistrings ['orders.button.label.delete']}icon =ui-icon-trash
update =ordersajax =true onclick =confirmDelete.show()/>
< / p:contextMenu>

但是这根本不行。没有显示任何菜单。



2)将两个上下文菜单放在outputPanel中,并更新面板。这与我的第一次尝试相同。即正确呈现菜单项,但丢失选择

 < p:outputPanel id =contextMenuPanelautoUpdate =true> ; 
< p:contextMenu id =contextMenu1Selectedfor =ordersrendered =#{ordersController.renderDisplayDocument}>
[菜单项]
< / p:contextMenu>

< p:contextMenu id =contextMenuManySelectedfor =ordersrendered =#{ordersController.renderDeleteDocuments}>
[菜单项]
< / p:contextMenu>
< / p:outputPanel>

3)使用控制器提供的menuModel定义contextMenu模型,该模型本身有两个可用于这两种情况,并根据所选项目的数量提供正确的情况。另外在输出面板中

 < p:outputPanel id =contextMenuPanelautoUpdate =true> 
< p:contextMenu id =contextMenufor =ordersmodel =#{ordersController.menuModel}/>
< / p:outputPanel>>

这样也不行。 MenuItems正确呈现,但多项选择与以前一样丢失。



我已经用尽了我所知道的选项。有没有人成功地通过多选择方式实现了数据库的动态上下文菜单?





还是有人有任何进一步的想法可以工作吗?



干杯。

解决方案

也许太晚了,但这里是我的解决方案...



上下文菜单与javascript: / p>

 < p:contextMenu id =searchResultTableContextMenuIdfor =searchResultTableIdbeforeShow =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-downloadajax = 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来修复上下文菜单隐藏的问题,如果在ajax事件contextMenu中更新 - >
< script type =text / javascript>
var currentEvent;
$(document).ready(function(){
PrimeFaces.widget.ContextMenu.prototype.show = function(e){
//隐藏其他contextmenus如果有
$ (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();

//窗口边界的碰撞检测
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.b eforeShow.call(this);
}

this.jq.css({
'left':left,
'top':top,
'z-index' ++ PrimeFaces.zindex
})。show();

e.preventDefault();
};
});
< / script>

dataTable需要处理一些用于上下文菜单显示和更新的ajax事件:

 < p:dataTable id =searchResultTableId...> 
< p:ajax event =rowSelectupdate =:searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId/>
< p:ajax event =rowUnselectupdate =:searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId/>
< p:ajax event =toggleSelectupdate =:searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId/>
< p:ajax event =rowSelectCheckboxupdate =:searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId/>
< p:ajax event =rowUnselectCheckboxupdate =:searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuId/>
< p:ajax event =contextMenuupdate =:searchInstancesFormId:listResultTabViewId:searchResultTableContextMenuIdoncomplete =PF('searchResultTableContextMenuVar')show(currentEvent); />
< / p:dataTable>


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

My first idea was to use the "rendered" option of individual menu items, which is set in the controller bean. This sort-of works, as indeed the correct menu items were displayed. The problem is that using the rendered functionality of the menuitems had the effect that the selection is lost on the datatable, defeating the purpose 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 looking for solutions in this and other forums, finding some hints, and figuring out a few alternatives myself, I made several other attempts including:

1) using two complete context menus: one for when one item is selected, and other for when many items are selected, and using the rendered option on the context menus themselves, rather than their items.

In this case the rowSelect and rowUnselect events update both

    <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 this did not work at all. No menus were ever shown.

2) Placing the two context menus inside an outputPanel, and updating the panel. This had the same result as my first attempt. i.e. menu-items rendered correctly but losing the 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) Defining the contextMenu model using a menuModel provided by the controller, which itself has two models available for the two cases and delivers the correct one depending on the number of selected items. Also in an output Panel

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

This also did not work. MenuItems correctly rendered, but multi-selections lost as before.

I have exhausted the options i am aware of.

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

Or does anyone have any further ideas that might work?

Cheers.

解决方案

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 needs to handle some ajax events for context menu showing and updating:

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

这篇关于为Primefaces多选Datatable实现动态ContextMenu的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-31 03:20