New Features in Dojo Grid 1.2

October 22nd, 2008 - by Bryan Forbes

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

<div dojoType="dijit.layout.BorderContainer" jsid="container"
    id="container" design="headline">

    <div dojoType="dijit.layout.ContentPane" region="top">
        <div class="headerWrapper">
            <h1>Gasket Lookup</h1>
        </div>
    </div>
</div>
 
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:

<div id="container" dojoType="dijit.layout.BorderContainer" design="headline">
    <div dojoType="dijit.layout.ContentPane" region="top">
        <div class="headerWrapper">
            <h1>Gasket Lookup</h1>
        </div>
    </div>
    <table id="gridNode" jsid="grid" dojoType="dojox.grid.DataGrid"
        query="{ part_num: ‘*’ }" store="jsonStore" rowsPerPage="20"
        region="center">

        <thead>
            <tr>
                <th field="part_num" width="auto">Part Number</th>
                <th field="type" formatter="formatType" width="auto">Type</th>
                <th field="thick" formatter="formatFraction"
                    width="auto">
Thickness</th>
                <th field="inner" formatter="formatFraction"
                    width="auto">
I.D.</th>
                <th field="outer" formatter="formatFraction"
                    width="auto">
O.D.</th>
                <th field="min_temp" formatter="formatDegrees"
                    width="auto">
Min. Temp. (F)</th>
                <th field="max_temp" formatter="formatDegrees"
                    width="auto">
Max. Temp. (F)</th>
                <th field="max_pres" width="auto">Max. Pressure</th>
            </tr>
        </thead>
    </table>
</div>
 

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

<table id="gridNode" jsid="grid" dojoType="dojox.grid.DataGrid"
    query="{ part_num: ‘*’ }" store="jsonStore" rowsPerPage="20"
    selectionMode="single">

    <thead>
        <tr>
            <th field="part_num">Part Number</th>
            <th field="type" formatter="formatType">Type</th>
            <th field="thick" formatter="formatFraction">Thickness</th>
            <th field="inner" formatter="formatFraction">I.D.</th>
            <th field="outer" formatter="formatFraction">O.D.</th>
            <th field="min_temp" formatter="formatDegrees">Min. Temp. (F)</th>
            <th field="max_temp" formatter="formatDegrees">Max. Temp. (F)</th>
            <th field="max_pres">Max. Pressure</th>
        </tr>
    </thead>
</table>
 

[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):

<table id="gridNode" jsid="grid" dojoType="dojox.grid.DataGrid"
    query="{ part_num: ‘*’ }" store="jsonStore" rowsPerPage="20"
    columnReordering="true">

    <thead>
        <tr>
            <th field="part_num">Part Number</th>
            <th field="type" formatter="formatType">Type</th>
            <th field="thick" formatter="formatFraction">Thickness</th>
            <th field="inner" formatter="formatFraction">I.D.</th>
            <th field="outer" formatter="formatFraction">O.D.</th>
            <th field="min_temp" formatter="formatDegrees">Min. Temp. (F)</th>
            <th field="max_temp" formatter="formatDegrees">Max. Temp. (F)</th>
            <th field="max_pres">Max. Pressure</th>
        </tr>
    </thead>
</table>
 

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:

<div dojoType="dijit.Menu" jsid="gridMenu" id="gridMenu" style="display: none;">
    <div dojoType="dijit.MenuItem" onClick="alert(’Hello world’);">
        Enabled Item
    </div>
    <div dojoType="dijit.MenuItem" disabled="true">Disabled Item</div>
    <div dojoType="dijit.MenuSeparator"></div>
    <div dojoType="dijit.MenuItem" iconClass="dijitEditorIcon dijitEditorIconCut"
        onClick="alert(’not actually cutting anything, just a test!’)">
Cut</div>
    <div dojoType="dijit.MenuItem" iconClass="dijitEditorIcon dijitEditorIconCopy"
        onClick="alert(’not actually copying anything, just a test!’)">
Copy</div>
    <div dojoType="dijit.MenuItem" iconClass="dijitEditorIcon dijitEditorIconPaste"
        onClick="alert(’not actually pasting anything, just a test!’)">
Paste</div>
</div>
 
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:

<table id="gridNode" jsid="grid" dojoType="dojox.grid.DataGrid"
    query="{ part_num: ‘*’ }" store="jsonStore" rowsPerPage="20"
    headerMenu="gridMenu">

    <thead>
        <tr>
            <th field="part_num">Part Number</th>
            <th field="type" formatter="formatType">Type</th>
            <th field="thick" formatter="formatFraction">Thickness</th>
            <th field="inner" formatter="formatFraction">I.D.</th>
            <th field="outer" formatter="formatFraction">O.D.</th>
            <th field="min_temp" formatter="formatDegrees">Min. Temp. (F)</th>
            <th field="max_temp" formatter="formatDegrees">Max. Temp. (F)</th>
            <th field="max_pres">Max. Pressure</th>
        </tr>
    </thead>
</table>
 

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

<table id="gridNode" jsid="grid" dojoType="dojox.grid.DataGrid"
    query="{ part_num: ‘*’ }" store="jsonStore" rowsPerPage="20"
    columnReordering="true">

    <thead>
        <tr>
            <th field="part_num">Part Number</th>
            <th field="type" formatter="formatType">Type</th>
            <th field="thick" formatter="formatFraction">Thickness</th>
            <th field="inner" formatter="formatFraction">I.D.</th>
            <th field="outer" formatter="formatFraction">O.D.</th>
            <th field="min_temp" formatter="formatDegrees" hidden="true">
                Min. Temp. (F)
            </th>
            <th field="max_temp" formatter="formatDegrees" hidden="true">
                Max. Temp. (F)
            </th>
            <th field="max_pres" hidden="true">Max. Pressure</th>
        </tr>
    </thead>
</table>
 

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:

<script type="text/javascript" src="js/dojo/dojo.js"></script>
<script type="text/javascript">
    dojo.getAttr = dojo.attr;
</script>
 

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:

<div dojoType="dijit.Menu" jsid="gridMenu" id="gridMenu" style="display: none;">
    <div dojoType="dojox.widget.PlaceholderMenuItem" label="GridColumns"></div>
</div>
 

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

Bookmark and Share

68 Responses to “New Features in Dojo Grid 1.2”

  1. Marco says:

    First of all, thank you Brian for this great article. I know it’s possible to make the whole grid reorderable by setting columnReordering to true, but is it possible to make this configuration at column level, i.e. making some columns reorderable and others not? In case it is, How can I do this? Thanks in advance.

  2. Tarun says:

    How can we add a row in the middle or top of a grid??I’ve been searching it but the only example i got was adding it to last.Thanks in Advance

  3. Satyanarayana says:

    Hi,
    I tried to run your example files using dojo 1.3. but the grid is not shown. when i applied startup call on grid object, it’s getting displayed. please explain the reason. So to perform startup() call, i put a button in the page. but if that button pressed for more times, the grid size getting increased. please clarify the reason for this.

  4. Satyanarayana says:

    i created the grid using javascript code.

  5. Satyanarayana says:

    sorry….. the grid size is getting increased when i click on column header for sorting the content.

  6. Eric says:

    is it possible to filter the list from a selected value in the title row?

  7. Sathya says:

    Can we able to apply/update the cell value if we move out of the grid?

    I tried “commitOnBlur” as true in _base.js but still onblur event listener is not updating the value.

    Any workaround available for onblur issue?

    I am using Dojo 1.2.

  8. Dylan says:

    I’m looking for a way to set a custom editor specific to a cell and not the entire column. Has this been done already, if not where would the connection be set?

  9. Jamie says:

    Does anyone know a way or have an example where the grid is displayed as a properties type grid. Where the field columns are on the left and the field values are on the right?

  10. Leon says:

    I need to use DataGrid,but the data i receive from other channel-pushlet via ajax connection,I just need to add new row to grid and every 10ms i”ll populate the cells myself,so i don’t have url for any version of Store that requires data sources.
    How i can add new rows without using ***Store?

  11. kaczmar2 says:

    Does anyone have an example of the dojox.grid.DataGrid being used as the base class for a custom widget. I cannot get my custom widget to render data when I inherit from the DataGrid.

  12. Vinoth says:

    I need to add an custom attribute in a HTML TR element in the data grid created. Can you help me to sort out this issue ?

  13. Jekser says:

    What is about “commitOnBlur” question ???
    I’m using dojo 1.4 and have the same problem :(
    I need to validate user input, and prevent cell blur by error.

  14. I’m also looking for a way to set a custom editor specific to a cell and not the entire column. Has this been done already, if not where would the connection be set?

  15. neil says:

    This was awesome help, thank you!

    Thought I’d note my final version of the context-menu version. While there is a link to your programmatic example, the menu is still in markup. I’m building out different grids for different users with user-defined “views” so to create this inside my class was important:

    var selectFieldsMenu = new dijit.Menu({jsId:”selectFieldsMenu”});
    var selectFieldsInnerMenu = new dojox.widget.PlaceholderMenuItem({label:”GridColumns”});
    selectFieldsMenu.addChild(selectFieldsInnerMenu);

    this.userGrid = new dojox.grid.DataGrid({……, headerMenu:selectFieldsMenu

    …works! Thanks again!

    Suggested addition (anybody?): HOW to detect the event of user-column resizing??? Nobody on IRC seems to have the answer, so far.

  16. dave42 says:

    Neil,

    The following snippet of code worked for me to hook into user-column resizing:

    dojo.forEach(dijit.byId(”layout_grid”).views.views, function(view) {
    dojo.connect(view.header, “doResizeNow”, function(inDrag, data) {
    console.log(”Row “+inDrag.index+” set to width “+data.w);
    });
    });

    The id of my grid is “layout_grid”. I hope the rest is clear. Still looking for a way to set a custom editor per-cell – I will post here if I find it.

  17. neil says:

    Thanks, Dave42,

    I tried your code and I appreciate the way it got me thinking, but it didn’t do it for me. Still, it was great searching for an answer today and finding this. Here is my working version to detect column resize. What a booger. I tried to find an event for forever. I guess I don’t get inheritance in dojo-land just yet. (dojo.exists helps)

    this.connect(this.grid, “onResizeColumn”, function(){
    console.log(”onResizeColumn, mark in view list”);
    });

    Here this is my widget, but could be dojo.connect.
    Also, this.grid is my widget’s grid and could be a dijit.byId as Dave uses.

  18. Mat says:

    Hi guys!
    I love the DataGrid but how do I deselect a row???
    I have a datagrid with ’selectionMode=single’ and I want to be able to deselect currently selected row. How do I do that?
    Mat

Leave a Reply