Events

As we alluded to in the last few pages, selection and cell editing is pointless without some kind of background processing. So how do you hook code into these places? Through Dojo's event model, of course!

Editing Changes

If you're using a writable dojo.data datastore, you simply hook your procedures into the dojo.data Notification API. Suppose in our running example, we make the Description field editable:

cells: [[
    {name: 'Namespace', field:0, width:"30em"}, 
    {name: 'Description', field:3, width:"30em",
        editor: dojox.grid.editors.Dijit }
  ]
],

Then, we place the hook into dojo.data.Notification's onSet extension point:

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}
<div dojoType="dojo.data.ItemFileWriteStore"
        jsId="jsonStore" url="dijits.txt">

    <script type="dojo/connect" event="onSet" args="item,attr,oldVal,newVal">
       console.debug("About to change "+attr+" from "+oldVal+" to "+newVal);
       // Save the record with dojo.xhrPost or your favorite remote method
    </script>
</div>

Here is the entire source code. Note how we place the layout initialization code in a dojo/method block inside the Grid tag. That's due to the editor class dojox.grid.editors.Dijit in the view definition. When you're using CDN, the dojox.grid.editors package is not available directly after the dojo.require., so we can't place the initialization code after it (as we did in our previous examples). By using a dojo/method, we can place this code close to its use (the Grid tag) and it's guaranteed to run after all dojo.require'd modules have loaded. You can also use dojo.addOnLoad to accomplish this.

/* GeSHi (C) 2004 - 2007 Nigel McNie (http://qbnz.com/highlighter) */ .geshifilter {font-family: monospace;} .geshifilter .imp {font-weight: bold; color: red;} .geshifilter .kw1 {color: #b1b100;} .geshifilter .kw2 {color: #000000; font-weight: bold;} .geshifilter .kw3 {color: #000066;} .geshifilter .coMULTI {color: #808080; font-style: italic;} .geshifilter .es0 {color: #000099; font-weight: bold;} .geshifilter .br0 {color: #66cc66;} .geshifilter .st0 {color: #ff0000;} .geshifilter .nu0 {color: #cc66cc;} .geshifilter .sc0 {color: #00bbdd;} .geshifilter .sc1 {color: #ddbb00;} .geshifilter .sc2 {color: #009900;}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <title>Test dojox.Grid Editing</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
    <style type="text/css">
        @import "http://o.aolcdn.com/dojo/1.0.0/dojox/grid/_grid/tundraGrid.css";
        @import "http://o.aolcdn.com/dojo/1.0.0/dijit/themes/tundra/tundra.css";
        @import "http://o.aolcdn.com/dojo/1.0.0/dojo/resources/dojo.css"
        body {
            font-size: 0.9em;
            font-family: Geneva, Arial, Helvetica, sans-serif;
        }
        .heading {
            font-weight: bold;
            padding-bottom: 0.25em;
        }
               
        #grid {
            border: 1px solid #333;
            width: 40em;
            height: 30em;
        }
    </style>
    <script type="text/javascript" src="http://o.aolcdn.com/dojo/1.0.0/dojo/dojo.xd.js"
            djConfig="isDebug:false, parseOnLoad: true">
</script>
    <script type="text/javascript">
        dojo.require("dojo.data.ItemFileWriteStore");
        dojo.require("dojox.grid.Grid");
        dojo.require("dojox.grid._data.model");
        dojo.require("dojox.grid.editors");
        dojo.require("dojo.parser");
   
</script>
</head>
<body class="tundra">
<div class="heading">Grid Events</div>
    <div dojoType="dojo.data.ItemFileWriteStore"
        jsId="jsonStore" url="dijits.txt">

        <script type="dojo/connect" event="onSet" args="item,attr,oldVal,newVal">
            console.debug("About to change "+attr+" from "+oldVal+" to "+newVal);
        </script>
    </div>
    <div dojoType="dojox.grid.data.DojoData" jsId="model"
        rowsPerPage="20" store="jsonStore" query="{ namespace: '*' }"
        clientSort="true">

    </div>
    <div id="grid" elasticView="2" dojoType="dojox.Grid" model="model"
        jsId="thisGrid">

        <script type="dojo/method">
            var view1 = {
                cells: [[
                    {name: 'Namespace', field:0, width:"30em"},
                    {name: 'Description', field:3, width:"30em"}
                  ],
                  [
                    {name: 'Summary', field:2, colspan:2,
                     editor: dojox.grid.editors.Dijit }
                  ]
                ]
            };
            var rowbar = {
               type: 'dojox.GridRowView', width: '20px'
            };
            var fixedColumn = {
                 noscroll: true,
                 cells: [[ {name: 'Class', field:1} ]]
            };
           
            // When you initialize inside the dojo/method script, you must set the
            // structure manually.
            var layout = [ rowbar, fixedColumn, view1 ];
            thisGrid.setStructure(layout);
        </script>
       </div>
</body>
</html>

You can read more on the dojo.data Notification API in Part 3 of the book, but here are the basics for your Grid needs:

  • onSet: function(/* item */ item, /* attribute-name-string */ attribute, /* object | array */ oldValue, /* object | array */ newValue ) - called after any cell is edited and saved.
  • onNew: function(/* item */ newItem,) - called after a row is added to the grid.
  • onDelete: function(/* item */ deletedItem) - called after a row is deleted

Low-Level Events

For more granular event processing, you can hook into Grid events. Each event calls the function you provide, passing back the event object. If e is the event, the interesting stuff is in:

  • e.rowIndex: the row number
  • e.cell.index: the column (cell) number. Taken with e.rowIndex, effectively gives you coordinates of a cell event.
  • e.keyCode: keystroke value, only applicable to keydown event.
Entity click/double click mouse over/out right click
Data Cell onCellClick
onCellDblClick
onCellMouseOver
onCellMouseOut
onCellContextMenu
Hdr Cell onHeaderCellClick
onHeaderCellDblClick
onHeaderCellMouseOver
onHeaderCellMouseOut
onHeaderCellContextMenu
Data Row onRowClick
onRowDblClick
onRowMouseOver
onRowMouseOut
onRowContextMenu
Hdr Row onHeaderClick
onHeaderDblClick
onHeaderMouseOver
onHeaderMouseOut
onHeaderContextMenu