Customize context menu position in Devextreme datagrid

|
| By Webner

How To customize default position of context menu in Devextreme datagrid using jquery?

Context Menu in devextreme is a set of menu items/links that appears on right click of some element like button or image by the user. By default Position inside the context menu can be specified as ‘left’ , ‘right’ ,’top’ ,’bottom’ ,’center’. If no position is specified then, context menu appears at the position where current clicked cursor point.

Screenshot below shows the specified left top position of context menu.
Customize context menu position in Devextreme datagrid

To set the context menu with respect to the DataGrid, we need to use the target attribute of the devextreme context menu which is taken as Id attribute of the grid. After this, on right click of grid context menu opens. Context Menu takes the whole Datagrid size as a context to specify its location within the grid using position attribute.

The target here is to set the context menu position with respect to row position and on simple click of column of any grid row i.e on left click.

Below function contains the code to create context menu with respect to Devextreme Jquery Datagrid.

///////////////Public Variables ////////////////
var contextMenu=null;
var clickedRow = 0;
//////////////////////////////////////////////////////////
function createGridContextMenu() {

    contextMenu = $("#documentGridContextMenu").dxContextMenu({
        width: 200,
        items: menuItems,
        target: '#mydocumentGrid,   // specify the grid id in the target attribute of the context menu
        selectionMode: "single",
        selectByClick: true,
        position: { at: 'left top', my: 'left top' },
        onShown: function (e) {
            setContextmenuPosition();    // On shown event of context menu, this method is invoked , 
                                                              //which is discussed below
        },
        onItemClick: function (e) { ……. },
    }).dxContextMenu('instance');

} 

Function below contains the code of data grid with custom cell template with down arrow icon, on click of which ‘onMenuClick’

 $("#mydocumentGrid").dxDataGrid({
………………….
columns: [{
         caption: '', allowHiding: false, visible: true, width: 50, alignment: 'center',
         cellTemplate: function (container, options) { //custom cell template with arrow icon to open context   
                                                                                Menu on click event
                       $('')
                       .attr("title", options.rowIndex)
                       .click(function (e) {
                           onMenuClick(e);                      // on click event, this method is invoked
                       }).appendTo(container);
            }
         },
……………...

}] 

Function code below handles the click event of cell in a row, where we firstly select the row and context menu show event is invoked to display the context menu.

 function onMenuClick(e) {
    var original = e.target;
    var rowIndex = original.title;    // Row Index of row containing the clicked cell.
    var dataGrid = $("#mydocumentGrid").dxDataGrid('instance');
    var sourceData = dataGrid.option("dataSource");

    var selectedData = dataGrid.getSelectedRowsData();
    var selectRowIndex = new Array();
    for (var i = 0; i < selectedData.length; i++) {
        var index = sourceData.indexOf(selectedData[i]);
        if (index != -1)
            selectRowIndex[i] = index;
    }
    if (selectRowIndex.indexOf(rowIndex) == -1)
        selectRowIndex.push(rowIndex);

    dataGrid.selectRowsByIndexes(selectRowIndex);
    clickedRow  = parseInt(rowIndex); // save the row index of clicked cell for further use. 
    contextMenu.show();                                // display the context menu
    
} 

When context menu shown method is invoked, then class ‘dx-overlay’ and ‘dx-menu-base’ are appended in the devextreme internal div element of context menu and dx-has-context-menu is removed. We can set the context menu position using these classes.

But while setting the new position, context menu appears first on the “left top” position and then appears at the new position. To resolve this, we can use the following css to make the context menu invisible initially. We can change the display css attribute to “block” (handled in the next function code block):

 .dx-context-menu:not(.dx-has-context-menu){ 
   display:none;             // before making changes in position, hide context menu div 
} 

Later on this can be set to display:block to make it visible after correct positioning is achieved.

Below is the function code that is used to modify the position of the context menu. Where the position is calculated based on grid available height of elements and custom margin is supplied to the devextreme element of the Devextreme context menu with classes dx-overlay-content, dx-resizable, dx-context-menu and dx-menu-base.

 function setContextmenuPosition() {
    var rowIndex = clickedRow;  // row index of clicked cell 
    var heightOfContextMenu =    
                              $(".dx-overlay-content.dx-resizable.dx-context-menu.dx-menu-base").height();
    
   var gridInstance = $("#mydocumentGrid").dxDataGrid("instance");
   var gridHeight = $(gridId).height();

   var gridHeaderPanelHeight = 
                            $("#mydocumentGrid .dx-datagrid-header-panel").outerHeight();

    var gridHeaderRowHeight = $("#mydocumentGrid .dx-datagrid-headers").outerHeight();
    var selectedrows = gridInstance.getSelectedRowsData();
    var positionOffisetFromTop="0";
    var topSpace = gridHeaderPanelHeight + gridHeaderRowHeight + gridHeaderRowHeight*rowIndex;
    var bottomSpace = gridHeight - topSpace;
    var centerpointgridRow = gridHeaderRowHeight * 0.5;
    if (topSpace > bottomSpace){// take the upper position from row if there is more space above the row          
        positionOffisetFromTop = topSpace+ centerpointgridRow- heightOfContextMenu;
    }
    else if (topSpace < bottomSpace) // take the lower position from row if space below row is more.
        positionOffisetFromTop = topSpace + centerpointgridRow;
    else {                                      // show in center
        positionOffisetFromTop = topSpace - (heightOfContextMenu * 0.5);
    }
    $(".dx-context-menu.dx-overlay-content").css("top",    
          positionOffisetFromTop);
    $(".dx-context-menu.dx-overlay-content").css("display", "block"); 
                          // set the display “block” css for the context menu div after making changes in position.
} 

Screenshot below contains the modified position of context menu:
Customize context menu position in Devextreme datagrid

Leave a Reply

Your email address will not be published. Required fields are marked *