The last article about the Dojo Grid focused on what has changed when creating a grid using Dojo 1.2. In this article we will be covering five new features of the Dojo 1.2 Grid: Dijit interoperability, selection modes, reorderable columns, header context menus, and column hiding. The examples in this article can be downloaded in a tarball (which includes the build profile I used) so you can play along from home!

Dijit Interoperability

The new grid now works with Dijit’s layout widgets natively. This comes in handy when you’re working on a project that needs to resize with the browser window. I’ll be using dijit.layout.BorderContainer to show this off (for more information on dijit.layout.BorderContainer, check out the documentation at dojotoolkit.org or dojocampus.org):

Gasket Lookup

dojo.addOnLoad(function(){
    grid = new dojox.grid.DataGrid({
        query: { part_num: '*' },
        store: jsonStore,
        structure: [
            { field: "part_num", name: "Part Number", width: "auto" },
            { field: "type", name: "Type", formatter: formatType,
                sortDesc: true, width: "auto" },
            { field: "thick", name: "Thickness", formatter: formatFraction,
                width: "auto" },
            { field: "inner", name: "I.D.", formatter: formatFraction,
                width: "auto" },
            { field: "outer", name: "O.D.", formatter: formatFraction,
                width: "auto" },
            { field: "min_temp", name: "Min. Temp. (F)", formatter: formatDegrees,
                width: "auto" },
            { field: "max_temp", name: "Max. Temp. (F)", formatter: formatDegrees,
                width: "auto" },
            { field: "max_pres", name: "Max. Pressure", width: "auto" }
        ],
        rowsPerPage: 20,
        region: 'center'
    });
    container.addChild(grid);
    grid.startup();
});

Or using markup:

Gasket Lookup

Part Number Type Thickness I.D. O.D. Min. Temp. (F) Max. Temp. (F) Max. Pressure

[Live Example]
Programmatic Example | Markup Example

You might also note that creating the grid programmatically requires an extra call to grid.startup(). This is a change to follow the way Dijit widgets allow for delaying rendering of the widget until all child widgets have been created on the page. In markup, this gets called automatically by the Dojo parser.

Selection Modes

For 1.2, we refined the way selection functions by adding some new modes: none, single, multiple, and extended. “None” does exactly what you think it would: no selections can be made. “Single” only allows one row to be selected at a time. “Multiple” allows multiple rows to be selected. There are no keyboard modifiers: to deselect a row you click on it again. “Extended” allows single rows and ranges of rows to be selected. This is the default behavior and behaves the same as the 1.1 grid. In order to use the different modes you would pass them as a property to the widget constructor:

grid = new dojox.grid.DataGrid({
    query: { part_num: '*' },
    store: jsonStore,
    structure: [
        { field: "part_num", name: "Part Number" },
        { field: "type", name: "Type", formatter: formatType, sortDesc: true },
        { field: "thick", name: "Thickness", formatter: formatFraction },
        { field: "inner", name: "I.D.", formatter: formatFraction },
        { field: "outer", name: "O.D.", formatter: formatFraction },
        { field: "min_temp", name: "Min. Temp. (F)", formatter: formatDegrees },
        { field: "max_temp", name: "Max. Temp. (F)", formatter: formatDegrees },
        { field: "max_pres", name: "Max. Pressure" }
    ],
    rowsPerPage: 20,
    selectionMode: 'single'
}, 'gridNode');
sel.startup();

Or in markup:

Part Number Type Thickness I.D. O.D. Min. Temp. (F) Max. Temp. (F) Max. Pressure

[Live Example]
Programmatic Example | Markup Example

Reorderable Columns

For simple cell layouts in a view (one row of cells), we have implemented column reordering using Dojo’s drag and drop architecture. To use it, just pass columnReordering: true to your grid constructor:

grid = new dojox.grid.DataGrid({
    query: { part_num: '*' },
    store: jsonStore,
    structure: [
        { field: "part_num", name: "Part Number" },
        { field: "type", name: "Type", formatter: formatType, sortDesc: true },
        { field: "thick", name: "Thickness", formatter: formatFraction },
        { field: "inner", name: "I.D.", formatter: formatFraction },
        { field: "outer", name: "O.D.", formatter: formatFraction },
        { field: "min_temp", name: "Min. Temp. (F)", formatter: formatDegrees },
        { field: "max_temp", name: "Max. Temp. (F)", formatter: formatDegrees },
        { field: "max_pres", name: "Max. Pressure" }
    ],
    rowsPerPage: 20,
    columnReordering: true
}, 'gridNode');
grid.startup();

Or using markup (passing columnReordering="true" to the node):

Part Number Type Thickness I.D. O.D. Min. Temp. (F) Max. Temp. (F) Max. Pressure

This new parameter will allow you to drag the columns within and between views within the originating grid that support dragging. Because of a bug in the 1.2 release, column reordering won’t work in IE7. This problem is being worked on for the 1.2.1 release. I’ve recorded a screencast that demonstrates how reordering will act (markup example) which you can watch if you click below.

[Screencast]
mp4 | theora

Header Context Menus

We’ve also made it much easier to add a header context menu to your grids. Just pass an instance of a dijit.Menu to your grid using the headerMenu property of the constructor:


grid = new dojox.grid.DataGrid({
    query: { part_num: '*' },
    store: jsonStore,
    structure: [
        { field: "part_num", name: "Part Number" },
        { field: "type", name: "Type", formatter: formatType, sortDesc: true },
        { field: "thick", name: "Thickness", formatter: formatFraction },
        { field: "inner", name: "I.D.", formatter: formatFraction },
        { field: "outer", name: "O.D.", formatter: formatFraction },
        { field: "min_temp", name: "Min. Temp. (F)", formatter: formatDegrees },
        { field: "max_temp", name: "Max. Temp. (F)", formatter: formatDegrees },
        { field: "max_pres", name: "Max. Pressure" }
    ],
    rowsPerPage: 20,
    headerMenu: gridMenu
}, 'gridNode');
grid.startup();

Or in markup:

Part Number Type Thickness I.D. O.D. Min. Temp. (F) Max. Temp. (F) Max. Pressure

[Live Example]
Programmatic Example | Markup Example

Column Hiding

One feature that was asked for in the new grid was the ability to hide columns. This can now be achieved two ways. The first is by setting the hidden attribute to a boolean in the cell definition:

grid = new dojox.grid.DataGrid({
    query: { part_num: '*' },
    store: jsonStore,
    structure: [
        { field: "part_num", name: "Part Number" },
        { field: "type", name: "Type", formatter: formatType, sortDesc: true },
        { field: "thick", name: "Thickness", formatter: formatFraction },
        { field: "inner", name: "I.D.", formatter: formatFraction },
        { field: "outer", name: "O.D.", formatter: formatFraction },
        { field: "min_temp", name: "Min. Temp. (F)", formatter: formatDegrees,
            hidden: true },
        { field: "max_temp", name: "Max. Temp. (F)", formatter: formatDegrees,
            hidden: true },
        { field: "max_pres", name: "Max. Pressure", hidden: true }
    ],
    rowsPerPage: 20
}, 'gridNode');
grid.startup();

Or in markup:

Part Number Type Thickness I.D. O.D.

There is a catch to this method if you use markup. Because of a bug in the Grid’s code (which will be fixed in 1.2.1), you must set dojo.getAttr to dojo.attr immediately after including Dojo:



The other way to hide columns is to call grid.layout.setColumnVisibility with the cell’s index and a boolean:

// to hide the third column
grid.layout.setColumnVisibility(2, false);

In the example I included, I added some dijit.form.CheckBox‘s to the page that correspond to each column in the layout. They are initialized with the column’s starting hidden value and clicking on them sets the column visibility:

var checkBoxes = [];
var container = dojo.byId('checkBoxContainer');
dojo.forEach(grid.layout.cells, function(cell, index){
    var cb = new dijit.form.CheckBox({
        checked: !cell.hidden

    });
    dojo.connect(cb, "onChange", function(newValue){
        grid.layout.setColumnVisibility(index, newValue);
    });

    var label = dojo.doc.createElement('label');
    label.innerHTML = cell.name;
    dojo.attr(label, 'for', cb.id);

    dojo.place(cb.domNode, container);
    dojo.place(label, container);
    dojo.place(dojo.doc.createElement("br"), container);

    checkBoxes.push(cb);
});

[Live Example]
Programmatic Example | Markup Example

Column hiding is all well and good, but some users want those CheckBoxes in a context menu. In order to do this, create your context menu like we did before, but add a dojox.widget.PlaceholderMenuItem to the menu and set its label attribute to “GridColumns” and the grid will take care of populating your menu with CheckBoxes:


[Live Example]
Programmatic Example | Markup Example

The Dojo Grid has become a very popular feature in Dojo. With version 1.2, we have made significant improvements towards ease of use, performance, and functionality. As you can imagine by our significant investment in making the grid better, it is widely used by SitePen’s developers. Since we can’t think of all use-cases, please continue sending us your feedback and suggestions for making the grid great. And if you’re in a bind or get stuck along the way, we’re here to help.