Dojo Data Grid – Part 18: EnhancedGrid Context Menus

The Menu plugin for the Dojo EnhancedGrid gives you the ability to add context menus to grid headers, rows, cells, and selected regions. In this post, I’ll show how to add the plugin and use it.

Dojo Data Grid Series

This post assumes you already have a Dojo Data Grid control set up to use the Dojo EnhancedGrid, based on the instructions in this post.

Load the Menu Plugin (and more)

The dojox.grid.enhanced.plugins.Menu module must be included on the page, so add it to the page resources. Properties > Resources > Add > Dojo Module…

Dojo Grid 18 - 1 - Modules

You also need to include the dijit menu and dijit menu item modules, since they’re required to build the context menus.

In this grid, I’m also including the Printer plugin, so I can trigger printing functions from the context menus.

Add the Plugin to the Grid

The first step made the plugin module available, but you also need to add it to the grid.

Go to the properties of the Dojo Data Grid > Dojo and click the Add button. Add two properties as shown here:

Dojo Grid 18 - 2 - Dojo Properties

This is the first example of including more than one EnhancedGrid plugin.

contextMenus is the name of a JavaScript object I’ve created to build the context menus (shown below).

Note: The row selection property is necessary in order to select rows in the grid.

Creating the Menus

To create the context menus, you create an object that contains properties for all of the context menus to define. You then add menu items to those menus and provide onClick events to take action when a context menu option is selected. Example code is shown below.

Using the Context Menus

Right click on column header
Dojo Grid 18 - 3 - Cell Header Context Menu

Right click on row selector
Dojo Grid 18 - 4 - Row Context Menu

Right click on a cell
Dojo Grid 18 - 5 - Cell Context Menu

Right click on a selected region
Dojo Grid 18 - 6 - Selected Region Context Menu

Context Menu Code

This code builds all four types of context menus and provides several actions:

// Set up the context menu object dijit menus
var contextMenus = {
  headerMenu: new dijit.Menu(),
  rowMenu: new dijit.Menu(),
  cellMenu: new dijit.Menu(),
  selectedRegionMenu: new dijit.Menu()

// Header Context Menu 
contextMenus.headerMenu.addChild(new dijit.MenuItem({label: "Print All", onClick:printAll}));
contextMenus.headerMenu.addChild(new dijit.MenuItem({label: "Print Selected", onClick:printSelected}));
contextMenus.headerMenu.addChild(new dijit.MenuItem({label: "Print Custom", onClick:printCustomized}));

// Row Context Menu
contextMenus.rowMenu.addChild(new dijit.MenuItem({label: "Display Click Location", onClick: rowDisplayClickLocation}));
contextMenus.rowMenu.addChild(new dijit.MenuItem({label: "Preview All", onClick:previewAll}));
contextMenus.rowMenu.addChild(new dijit.MenuItem({label: "Preview Selected", onClick:previewSelected}));
contextMenus.rowMenu.addChild(new dijit.MenuItem({label: "Preview Custom", onClick:previewCustomized}));

// Cell Context Menu
contextMenus.cellMenu.addChild(new dijit.MenuItem({label: "Display Click Location", onClick:cellDisplayClickLocation}));
contextMenus.cellMenu.addChild(new dijit.MenuItem({label: "Cell Menu Item 1", iconClass:'dijitEditorIcon dijitEditorIconCopy',onClick:function(){alert('copy!')}}));
contextMenus.cellMenu.addChild(new dijit.MenuItem({label: "Cell Menu Item 2", iconClass:'dijitEditorIcon dijitEditorIconPaste', onClick:function(){alert('paste!')}}));
contextMenus.cellMenu.addChild(new dijit.MenuItem({label: "Cell Menu Item 3", iconClass:'dijitEditorIcon dijitEditorIconCut', onClick:function(){alert('cut!')}}));

// Selected Region Context Menu
contextMenus.selectedRegionMenu.addChild(new dijit.MenuItem({label: "Context Info", onClick:function(){alert('row: ' + rowIndex + '\ncell: ' + cellIndex);}}));
contextMenus.selectedRegionMenu.addChild(new dijit.MenuItem({label: "Alert", onClick:function(){alert('selected region')}}));

Note: There are references to print and print preview functions from the Printer plugin for the EnhancedGrid. The code for those functions can be found in this post.

Working with the Click Context

What we’ve seen so far is fine to trigger javascript events, but, commonly, you will want to know the context of the click so you can execute logic targeted to that context.

At least 1 of 4 events is fired on the grid when the user right clicks to bring up a context menu:

  • onRowContextMenu(e)
  • onCellContextMenu(e)
  • onHeaderCellContextMenu(e)
  • onSelectedRegionContextMenu(e)

These event handlers all automatically get a handle to an event object (e) that has context information.

To use them, you need to attach a function to the event. In that function, you can set global JavaScript variables with context information. Then, in your context menu item functions, you can access that context information.

To retrieve and use the location of a context menu click, follow these steps:

1. Define global variables and the event handler function(s) in an Output Script tag or client-side JavaScript library:

var rowIndex;
var cellIndex;
// onRowContextMenu Event Handler
// Retrieves the rowIndex and cellIndex and stores them in a global variable for the menu click event handlers to reference
// NOTE: This event fires when clicking on a row selector or any cell in the row
function rowContextMenuEvent (e) {
  rowIndex = e.rowIndex;
  cellIndex = e.cellIndex;

// onCellContextMenu Event Handler
// Retrieves the rowIndex and cellIndex and stores them in a global variable for the menu click event handlers to reference
// NOTE: This event fires when clicking on any cell in the row. If an onRowContextMenu event handler is also defined, that will fire before this event handler fires.
function cellContextMenuEvent (e) {
  rowIndex = e.rowIndex;
  cellIndex = e.cellIndex;

2. Attach the event handler functions to the grid events on the onClientLoad event of your page. Here are examples of attaching to two of the events:

dojo.connect(dijit.byId("#{id:djxDataGrid1}"), "onRowContextMenu", rowContextMenuEvent);
dojo.connect(dijit.byId("#{id:djxDataGrid1}"), "onCellContextMenu", cellContextMenuEvent);

3. Create one or more menu action functions that refer to the global variables and then work with the context.

// Row context menu function to display the index of the row
function rowDisplayClickLocation () {
  alert('row index: ' + rowIndex + '\ncell index: ' + cellIndex);		
// Cell context menu function to display the index of the row and cell
function cellDisplayClickLocation () {
  alert('row index: ' + rowIndex + '\ncell index: ' + cellIndex);		

When the user right-clicks on a row selector to bring up the row context menu, the onRowContextMenu event function runs first, then the context menu is displayed, then the user selects an option from the context menu.

It is interesting to note that if you have event handlers defined for onRowContextMenu and onCellContextMenu, the onRowContextMenu event handler will run first, then the onCellContextMenu event handler will run second. If all you’re doing is getting the row and cell index where the click happend, you don’t even need the onCellContextMenu event handler.

Properties of the Event Object

Just for kicks, I ran a little script to tell me all of the properties available to that event object that’s provided to the context menu event handlers.

Here’s the list, in case you’d like to dig into any of them further:

rowNode, rowIndex, dispatch, grid, sourceView, cellNode, cellIndex, cell, type, target, currentTarget, eventPhase, bubbles, cancelable, timeStamp, defaultPrevented, stopPropagation, preventDefault, initEvent, stopImmediatePropagation, which, rangeParent, rangeOffset, pageX, pageY, isChar, screenX, screenY, mozMovementX, mozMovementY, clientX, clientY, ctrlKey, shiftKey, altKey, metaKey, button, buttons, relatedTarget, mozPressure, mozInputSource, initMouseEvent, initNSMouseEvent, getModifierState, originalTarget, explicitOriginalTarget, preventBubble, preventCapture, getPreventDefault, isTrusted, view, detail, initUIEvent, layerX, layerY, cancelBubble, NONE, CAPTURING_PHASE, AT_TARGET, BUBBLING_PHASE, MOUSEDOWN, MOUSEUP, MOUSEOVER, MOUSEOUT, MOUSEMOVE, MOUSEDRAG, CLICK, DBLCLICK, KEYDOWN, KEYUP, KEYPRESS, DRAGDROP, FOCUS, BLUR, SELECT, CHANGE, RESET, SUBMIT, SCROLL, LOAD, UNLOAD, XFER_DONE, ABORT, ERROR, LOCATE, MOVE, RESIZE, FORWARD, HELP, BACK, TEXT, ALT_MASK, CONTROL_MASK, SHIFT_MASK, META_MASK, SCROLL_PAGE_UP, SCROLL_PAGE_DOWN, MOZ_SOURCE_UNKNOWN, MOZ_SOURCE_MOUSE, MOZ_SOURCE_PEN, MOZ_SOURCE_ERASER, MOZ_SOURCE_CURSOR, MOZ_SOURCE_TOUCH, MOZ_SOURCE_KEYBOARD


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: