dojox.grid.EnhancedGrid

Project owner:Nathan Toone
Available:since V.1.4

Enhanced DataGrid adds numerous useful features to dojox.grid.

Introduction

EnhancedGrid (dojox.grid.EnhancedGrid) provides a rich set of features that enhance the capabilities of base DataGrid. The following accessible enhancements are implemented in Dojo 1.4:

  • Nested Sorting
  • Built-in support for Indirect Selection (radio buttons and check boxes)
  • Declarative context menus
  • Selecting multiple rows or columns by swiping
  • Moving multiple rows or columns with drag-n-drop

EnhancedGrid features are implemented as plugins which can be loaded on demand. As a result, the required features must first declared before they can be used.

<script type="text/javascript">
    dojo.require("dojox.grid.EnhancedGrid");
    dojo.require("dojox.grid.enhanced.plugins.DnD");
    dojo.require("dojox.grid.enhanced.plugins.Menu");
    dojo.require("dojox.grid.enhanced.plugins.NestedSorting");
    dojo.require("dojox.grid.enhanced.plugins.IndirectSelection");
    dojo.require("dojox.data.CsvStore");

    dojo.addOnLoad(function(){
      // our test data store for this example:
      var store = new dojox.data.CsvStore({ url: '{{ dataUrl }}dojox/grid/tests/support/movies.csv' });

      // set the layout structure:
      var layout = [
          { field: 'Title', name: 'Title of Movie', width: '200px' },
          { field: 'Year', name: 'Year', width: '50px' },
          { field: 'Producer', name: 'Producer', width: 'auto' }
      ];

      // create a new grid:
      var grid = new dojox.grid.EnhancedGrid({
          query: { Title: '*' },
          store: store,
          rowSelector: '20px',
          structure: layout,
          plugins : {nestedSorting: true, dnd: true, indirectSelection: {name: "Selection", width:"70px", styles:"text-align: center;"}}
      }, document.createElement('div'));

      // append the new grid to the div "gridContainer4":
      dojo.byId("gridDiv").appendChild(grid.domNode);

      // Call startup, in order to render the grid:
      grid.startup();
    });
</script>
<div id="gridDiv" style="width: 100%; height: 100%;"></div>
<style type="text/css">
    @import "{{ baseUrl }}dojo/resources/dojo.css";
    @import "{{ baseUrl }}dijit/themes/{{ theme }}/{{ theme }}.css";
            @import "{{ baseUrl }}dojox/grid/enhanced/resources/{{ theme }}EnhancedGrid.css";
            @import "{{ baseUrl }}dojox/grid/enhanced/resources/EnhancedGrid_rtl.css";

    .dojoxGrid table {
        margin: 0;
    }

    html, body {
        width: 100%;
        height: 100%;
        margin: 0;
    }
</style>

Usage

The following steps show a typical usage of EnhancedGrid:

  1. Import related CSS
1
2
3
4
5
<style type="text/css">
    @import "../../../../dijit/themes/claro/claro.css";
    @import "../../enhanced/resources/claroEnhancedGrid.css";
    ...
</style>
  1. Declare required feature plugins
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<script type="text/javascript">
    // Required for all Enhanced features
    dojo.require("dojox.grid.EnhancedGrid");
    // Row/Column drag-drop feature
    dojo.require("dojox.grid.enhanced.plugins.DnD");
    // Declarative pop-up menu feature
    dojo.require("dojox.grid.enhanced.plugins.Menu");
    // Nested sorting feature
    dojo.require("dojox.grid.enhanced.plugins.NestedSorting");
    // Indirect selection(check box/radio button selection) feature
    dojo.require("dojox.grid.enhanced.plugins.IndirectSelection");
    ...
</script>
  1. Use features:
1
2
3
4
5
6
7
8
9
<div id="grid" dojoType="dojox.grid.EnhancedGrid"
    plugins="{nestedSorting: true, dnd: true, indirectSelection: true,  // Each required feature must be turned on
    menus:{
    headerMenu:'headerMenu',  //References menus defined declaratively below
    rowMenu:'rowMenu',
    cellMenu:'cellMenu',
    selectedRegionMenu:'selectedRegionMenu'}}"
    ...>
</div>

Nested Sorting

This feature enhances the single sorting feature of base DataGrid. Nested sorting allows users to sort on one or more columns concurrently and also control the sort direction and order. Finally, columns can be removed from the sort without disturbing the rest of the sort.

<script type="text/javascript">
    dojo.require("dojox.grid.EnhancedGrid");
    dojo.require("dojox.grid.enhanced.plugins.NestedSorting");
    dojo.require("dojox.data.CsvStore");

    dojo.addOnLoad(function(){
      // our test data store for this example:
      var store = new dojox.data.CsvStore({ url: '{{ dataUrl }}dojox/grid/tests/support/movies.csv' });

      // set the layout structure:
      var layout = [
          { field: 'Title', name: 'Title of Movie', width: '200px' },
          { field: 'Year', name: 'Year', width: '50px' },
          { field: 'Producer', name: 'Producer', width: 'auto' }
      ];

      // create a new grid:
      var grid = new dojox.grid.EnhancedGrid({
          query: { Title: '*' },
          store: store,
          clientSort: true,
          rowSelector: '20px',
          structure: layout,
          plugins : {nestedSorting: true}
      }, document.createElement('div'));

      // append the new grid to the div "gridContainer4":
      dojo.byId("gridDiv").appendChild(grid.domNode);

      // Call startup, in order to render the grid:
      grid.startup();
    });
</script>
<div id="gridDiv" style="width: 100%; height: 100%;"></div>
<style type="text/css">
    @import "{{ baseUrl }}dojox/grid/enhanced/resources/{{ theme }}EnhancedGrid.css";
    @import "{{ baseUrl }}dojox/grid/enhanced/resources/EnhancedGrid_rtl.css";

    .dojoxGrid table {
        margin: 0;
    }

    html, body {
        width: 100%;
        height: 100%;
        margin: 0;
    }
</style>

Usage

Using the nested sorting feature is pretty simple as shown below:

  • Declare nested sorting feature plugin
1
2
3
4
5
<script type="text/javascript">
    dojo.require("dojox.grid.EnhancedGrid");
    dojo.require("dojox.grid.enhanced.plugins.NestedSorting");
    ...
</script>
  • Use nested sorting feature

...with HTML markup

1
2
<div id="grid" store="store1" dojoType="dojox.grid.EnhancedGrid" plugins="{nestedSorting: true}" >
</div>

...with JavaScript

1
2
3
<script>
    var grid = new dojox.grid.EnhancedGrid({id: "grid", store: "store1", plugins: {nestedSorting: true}, ...}, dojo.byId("gridDiv"));
</script>

When nested sorting is enabled, you can also use comparatorMap for custom sorting; see dojo.data.ItemFileReadStore on DojoCampus.org for more details.

Scenario

The following are typical scenarios using nested sorts:

  • When there is no sorting established, a unary (single) sort caret is shown when the mouse hovers over a column. The upward direction of the caret reflects that this will result in an ascending sort.
../../_images/sort-1.new.png
  • Once the sort choice is selected for the 'Genre' column, the grid rows will be sorted ascending based on by the values in Genre. Note that the keyboard focus moves to the sort choice in response to the mouse click. The graphical label of the sort choice is a downward caret since the function would be a descending sort.
../../_images/sort-2.png
  • Then the nested sort tip is shown when the mouse hovers over a other column headers.
  • Clicking region "A" in the figure below will execute a nested sort, and the rows will be sorted by Artist in this example within Genre.
  • Clicking region "B" will reset the sort, and the rows will be sorted by Artist alone.
../../_images/nested-sort-1.new.png
  • Once a column is sorted ascending, the sort choice changes to a sort descending choice.
../../_images/descending-sort-1.png
  • Once a column is sorted descending, the sort choice changes to a 'remove sort' function (see the figure below). When a column is removed from the sort, other columns in the sort will be adjusted to reflect the new sort order. For example, Year would become the second column in the sort if it had previously been the third.
../../_images/remove-sort.png

To summarize, the sort choice cycles among sort-ascending, sort-descending, and remove sort functions.

There is no limit to the number of columns that may be in the sort.

Accessibility

Keyboard Support

Key Action
LEFT/RIGHT arrow keys Moves the keyboard focus among column headers and regions within a column header
SPACE key Chooses the sorting choice with the keyboard focus
  • The above keys are only effective when keyboard focus is within the column headers.

Screen Readers

ARIA attributes "aria-label" and "aria-sort" are used for screen readers.

Region ARIA Attribute ARIA Attribute Value
Select region aria-label Column name
Unary sort choice aria-sort Sorting state, e.g. "descending"
  aria-label
  • Normal sate - "Column 2 Genre single sort"
  • Hovered - "Column 2 Genre - Press space to choose descending nested sort"
Nested sort choice aria-sort Sorting state, e.g. "descending"
  aria-label
  • Normal sate - "Column 2 Genre nested sort sort position 1"
  • Hovered - "Column 2 Genre - Press space to choose descending nested sort"

Note: In Firefox v.3.5, JAWS10 doesn't announce all the above ARIA attributes appropriately. This will be addressed when newer JAWS and Firefox versions are released.

Built-in Support for Indirect Selection

This feature provides indirect row selection support either through

  • Radio buttons - for single row selection, and
  • Check boxes - for multiple row selections

Please note indirect selection is completely dependent on the selection mode of EnhancedGrid so check boxes are used for "extended" and "multiple" selection mode ("extended" is the default mode), and radio buttons are used for "single" selection mode. For more details of Grid selection modes, please refer to the specification of the base Grid.

<script type="text/javascript">
    dojo.require("dojox.grid.EnhancedGrid");
    dojo.require("dojox.grid.enhanced.plugins.IndirectSelection");
    dojo.require("dojox.data.CsvStore");

    dojo.addOnLoad(function(){
      // our test data store for this example:
      var store = new dojox.data.CsvStore({ url: '{{ dataUrl }}dojox/grid/tests/support/movies.csv' });

      // set the layout structure:
      var layout = [
          { field: 'Title', name: 'Title of Movie', width: '200px' },
          { field: 'Year', name: 'Year', width: '50px' },
          { field: 'Producer', name: 'Producer', width: 'auto' }
      ];

      // create a new grid:
      var grid = new dojox.grid.EnhancedGrid({
          query: { Title: '*' },
          store: store,
          clientSort: true,
          rowSelector: '20px',
          structure: layout,
          plugins : {indirectSelection: {name: "Selection", width:"70px", styles:"text-align: center;"}}
      }, document.createElement('div'));

      // append the new grid to the div "gridContainer4":
      dojo.byId("gridDiv").appendChild(grid.domNode);

      // Call startup, in order to render the grid:
      grid.startup();
    });
</script>
<div id="gridDiv" style="width: 100%; height: 100%;"></div>
<style type="text/css">
            @import "{{ baseUrl }}dojox/grid/enhanced/resources/{{ theme }}EnhancedGrid.css";
            @import "{{ baseUrl }}dojox/grid/enhanced/resources/EnhancedGrid_rtl.css";

    .dojoxGrid table {
        margin: 0;
    }

    html, body {
        width: 100%;
        height: 100%;
        margin: 0;
    }
</style>

Usage

  • Declare indirect selection feature plugin
1
2
3
4
5
<script type="text/javascript">
    dojo.require("dojox.grid.EnhancedGrid");
    dojo.require("dojox.grid.enhanced.plugins.IndirectSelection");
    ...
</script>
  • Use indirect selection feature with check boxes

... with HTML markup

1
2
<div id="grid" dojoType="dojox.grid.EnhancedGrid" plugins="{indirectSelection: true}" >
</div>

... with JavaScript

1
2
3
<script>
    var grid = new dojox.grid.EnhancedGrid({id: "grid", plugins: {indirectSelection: true}, ...}, dojo.byId('gridDiv'));
</script>
  • Use indirect selection feature with radio buttons

... with HTML markup

1
2
<div id="grid" dojoType="dojox.grid.EnhancedGrid" plugins="{indirectSelection: true}" selectionMode="single" ... >
</div>

... with JavaScript

1
2
3
<script>
    var grid = new dojox.grid.EnhancedGrid({id: "grid", plugins: {indirectSelection: true}, selectionMode: "single", ...}, dojo.byId('gridDiv'));
</script>
  • It is unlikely that the row headers will be desired when indirect selection is used. The following code removes the row headers from the grid.
1
2
3
4
5
6
7
//with HTML markup
<div id="grid" dojoType="dojox.grid.EnhancedGrid" plugins="{indirectSelection: true}" rowSelector="0px" ... />

//with Javascript
<script>
  var grid = new dojox.grid.EnhancedGrid({id: "grid", plugins: {indirectSelection: true}, rowSelector: "0px", ...}, dojo.byId('gridDiv'));
</script>

Scenario

  • Indirect selection by radio buttons
../../_images/radio-buttons.png
  • Indirect selection by check boxes

Besides selecting or deselecting rows by clicking on check boxes, the SHIFT key can be held during the 2nd click to select or deselect a range of rows.

../../_images/extended-selection-checkboxes.gif
  • An additional selection technique is to swipe through check boxes (mouse down on the first, drag through the adjacent check boxes and then release on the last).
../../_images/swipe-checkbox.gif

Accessibility

Keyboard Support

Key Action
UP/Down arrow keys Navigate keyboard focus across cells that contain radio buttons or check boxes
SPACE key
  • Radio button - select a row
  • Check box - select or de-select a row.
SHIFT + Click SHIFT + SPACE key Select or de-select a range of rows
SHIFT+ UP/Down arrow keys Extend the selection or de-selection - only for check boxes .
  • The above keys are only effective when keyboard focus is in the first column that contains radio buttons or check boxes.

Note that extended selection is also enabled through the row headers as well.

Tips

  • When the "Indirect Selection" feature is enabled, you could handle row selection programmatically as follows.
1
2
3
4
5
<script>
    for(var i = 0; i < selectedRows.length/*Array of selected row index*/; i++){
       grid.rowSelectCell.toggleRow(selectedRows[i], true);
    }
</script>
  • When in non-‘single’ selection mode, it’s also easy to select or deselect all rows by:
1
2
3
<script>
    dijit.byId("grid").rowSelectCell.toggleAllSelection(true|false);
</script>
  • Another handy usage is to enable or disable a check box or radio button for a certain row by:
1
2
3
<script>
    dijit.byId('grid').rowSelectCell.setDisabled(rowIndex, true|false);
</script>
  • A topic named "rowSelectionChangedTopic" will be published when row selections are changed. The topic can be subscribed to with the following code.
1
dojo.subscribe(dijit.byId('grid').rowSelectionChangedTopic, function(){...});
  • You can check whether a certain row is selected with the following code.
1
dijit.byId('grid').selection.selected[rowIndex] // returns true or false
  • It's also possible to make some styling customizations for the indirect selection column.
1
<div id="grid" dojoType="dojox.grid.EnhancedGrid" plugins="{indirectSelection:{name:'Selection',width:'70px',styles:'text-align:right;'}}" ...></div>

or

1
2
3
<script>
  var grid = new dojox.grid.EnhancedGrid({id:"grid", plugins:{indirectSelection:{name:"Selection",width:"70px",styles:"text-align:center;"}, ...}, dojo.byId('gridDiv'));
</script>

Declarative Context Menu

With this new feature, users can add context menus either through declarative HTML markup or JavaScript. The following menu types are supported:

  • Header cell menu
  • Cell menu
  • Row menu

...with HTML markup

<script type="text/javascript">
    dojo.require("dojox.grid.EnhancedGrid");
    dojo.require("dojox.grid.enhanced.plugins.Menu");
    dojo.require("dojox.data.CsvStore");

    dojo.addOnLoad(function(){
      // our test data store for this example:
      var store = new dojox.data.CsvStore({ url: '{{ dataUrl }}dojox/grid/tests/support/movies.csv' });

      // set the layout structure:
      var layout = [
          { field: 'Title', name: 'Title of Movie', width: '200px' },
          { field: 'Year', name: 'Year', width: '50px' },
          { field: 'Producer', name: 'Producer', width: 'auto' }
      ];

      // create a new grid:
      var grid = new dojox.grid.EnhancedGrid({
          query: { Title: '*' },
          store: store,
          clientSort: true,
          rowSelector: '20px',
          structure: layout,
          plugins : {menus:{headerMenu:"headerMenu", rowMenu:"rowMenu", cellMenu:"cellMenu", selectedRegionMenu:"selectedRegionMenu"}}
      }, document.createElement('div'));

      // append the new grid to the div "gridContainer4":
      dojo.byId("gridDiv").appendChild(grid.domNode);

      // Call startup, in order to render the grid:
      grid.startup();
    });
</script>
<div id="gridDiv" style="width: 100%; height: 100%;">
        <div dojoType="dijit.Menu" id="headerMenu"  style="display: none;">
                <div dojoType="dijit.MenuItem">Header Menu Item 1</div>
                <div dojoType="dijit.MenuItem">Header Menu Item 2</div>
                <div dojoType="dijit.MenuItem">Header Menu Item 3</div>
                <div dojoType="dijit.MenuItem">Header Menu Item 4</div>
        </div>
        <div dojoType="dijit.Menu" id="rowMenu"  style="display: none;">
                <div dojoType="dijit.MenuItem">Row Menu Item 1</div>
                <div dojoType="dijit.MenuItem">Row Menu Item 2</div>
                <div dojoType="dijit.MenuItem">Row Menu Item 3</div>
                <div dojoType="dijit.MenuItem">Row Menu Item 4</div>
        </div>
        <div dojoType="dijit.Menu" id="cellMenu"  style="display: none;">
                <div dojoType="dijit.MenuItem">Cell Menu Item 1</div>
                <div dojoType="dijit.MenuItem">Cell Menu Item 2</div>
                <div dojoType="dijit.MenuItem">Cell Menu Item 3</div>
                <div dojoType="dijit.MenuItem">Cell Menu Item 4</div>
        </div>
        <div dojoType="dijit.Menu" id="selectedRegionMenu"  style="display: none;">
                <div dojoType="dijit.MenuItem">Action 1 for Selected Region</div>
                <div dojoType="dijit.MenuItem">Action 2 for Selected Region</div>
                <div dojoType="dijit.MenuItem">Action 3 for Selected Region</div>
                <div dojoType="dijit.MenuItem">Action 4 for Selected Region</div>
        </div>
</div>
<style type="text/css">
            @import "{{ baseUrl }}dojox/grid/enhanced/resources/{{ theme }}EnhancedGrid.css";
            @import "{{ baseUrl }}dojox/grid/enhanced/resources/EnhancedGrid_rtl.css";

    .dojoxGrid table {
        margin: 0;
    }

    html, body {
        width: 100%;
        height: 100%;
        margin: 0;
    }
</style>

...with Javascript

<script type="text/javascript">
    dojo.require("dojox.grid.EnhancedGrid");
    dojo.require("dojox.grid.enhanced.plugins.Menu");
    dojo.require("dojox.data.CsvStore");

    dojo.addOnLoad(function(){
      // our test data store for this example:
      var store = new dojox.data.CsvStore({ url: '{{ dataUrl }}dojox/grid/tests/support/movies.csv' });

      // set the layout structure:
      var layout = [
          { field: 'Title', name: 'Title of Movie', width: '200px' },
          { field: 'Year', name: 'Year', width: '50px' },
          { field: 'Producer', name: 'Producer', width: 'auto' }
      ];

       //programmatic menus
            var menusObject = {
                    headerMenu: new dijit.Menu(),
                    rowMenu: new dijit.Menu(),
                    cellMenu: new dijit.Menu(),
                    selectedRegionMenu: new dijit.Menu()
            };
            menusObject.headerMenu.addChild(new dijit.MenuItem({label: "Header Menu Item 1"}));
            menusObject.headerMenu.addChild(new dijit.MenuItem({label: "Header Menu Item 2"}));
            menusObject.headerMenu.addChild(new dijit.MenuItem({label: "Header Menu Item 3"}));
            menusObject.headerMenu.addChild(new dijit.MenuItem({label: "Header Menu Item 4"}));
            menusObject.headerMenu.startup();

            menusObject.rowMenu.addChild(new dijit.MenuItem({label: "Row Menu Item 1"}));
            menusObject.rowMenu.addChild(new dijit.MenuItem({label: "Row Menu Item 2"}));
            menusObject.rowMenu.addChild(new dijit.MenuItem({label: "Row Menu Item 3"}));
            menusObject.rowMenu.addChild(new dijit.MenuItem({label: "Row Menu Item 4"}));
            menusObject.rowMenu.startup();

            menusObject.cellMenu.addChild(new dijit.MenuItem({label: "Cell Menu Item 1"}));
            menusObject.cellMenu.addChild(new dijit.MenuItem({label: "Cell Menu Item 2"}));
            menusObject.cellMenu.addChild(new dijit.MenuItem({label: "Cell Menu Item 3"}));
            menusObject.cellMenu.addChild(new dijit.MenuItem({label: "Cell Menu Item 4"}));
            menusObject.cellMenu.startup();

            menusObject.selectedRegionMenu.addChild(new dijit.MenuItem({label: "Action 1 for Selected Region"}));
            menusObject.selectedRegionMenu.addChild(new dijit.MenuItem({label: "Action 2 for Selected Region"}));
            menusObject.selectedRegionMenu.addChild(new dijit.MenuItem({label: "Action 3 for Selected Region"}));
            menusObject.selectedRegionMenu.addChild(new dijit.MenuItem({label: "Action 4 for Selected Region"}));
            menusObject.selectedRegionMenu.startup();


      // create a new grid:
      var grid = new dojox.grid.EnhancedGrid({
          query: { Title: '*' },
          store: store,
          clientSort: true,
          rowSelector: '20px',
          structure: layout,
          plugins : {menus: menusObject}
      }, document.createElement('div'));

      // append the new grid to the div "gridContainer4":
      dojo.byId("gridDiv").appendChild(grid.domNode);

      // Call startup, in order to render the grid:
      grid.startup();
    });
</script>
<div id="gridDiv" style="width: 100%; height: 100%;">

</div>
<style type="text/css">
            @import "{{ baseUrl }}dojox/grid/enhanced/resources/{{ theme }}EnhancedGrid.css";
            @import "{{ baseUrl }}dojox/grid/enhanced/resources/EnhancedGrid_rtl.css";

    .dojoxGrid table {
        margin: 0;
    }

    html, body {
        width: 100%;
        height: 100%;
        margin: 0;
    }
</style>

Usage

  • Declare menu feature plugin
1
2
3
4
5
<script type="text/javascript">
    dojo.require("dojox.grid.EnhancedGrid");
    dojo.require("dojox.grid.enhanced.plugins.Menu");
    ...
</script>
  • Use menu feature

... with HTML markup

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<div id="grid" dojoType="dojox.grid.EnhancedGrid"
    plugins="{menus:{headerMenu:’headerMenu‘, rowMenu:’rowMenu‘, cellMenu:’cellMenu‘, selectedRegionMenu:’selectedRegionMenu‘}}" ... >
    <div dojoType="dijit.Menu" id="headerMenu" style="display: none;">
        <div dojoType="dijit.MenuItem">Header Menu Item 1</div>
    </div>
    <div dojoType="dijit.Menu" id="rowMenu" style="display: none;">
        <div dojoType="dijit.MenuItem">Row Menu Item 1</div>
    </div>
    <div dojoType="dijit.Menu" id="cellMenu" style="display: none;">
        <div dojoType="dijit.MenuItem">Cell Menu Item 1</div>
    </div>
    <div dojoType="dijit.Menu" id="selectedRegionMenu" style="display: none;">
        <div dojoType="dijit.MenuItem">Action 1 for Selected Region</div>
    </div>
</div>

... with JavaScript (using a markup menu)

1
2
3
var grid = new dojox.grid.EnhancedGrid({id: "grid",
    plugins: {menus:{headerMenu:’headerMenu‘, rowMenu:’rowMenu‘, cellMenu:’cellMenu‘, selectedRegionMenu:’selectedRegionMenu‘}}, ...},
    dojo.byId('gridDiv'));

Tips

TODO: tips - bind events to onxxContextMenu(e)

Selecting Multiple Rows/Columns with Swipe

This feature provides a mechanism to select row(s) and column(s) via mouse clicking, swiping or keyboards.

Note:

  • This feature is implemented as part of the "DnD" plugin of EnhancedGrid.
  • Row headers and column select regions are the only places where this feature is effective.

The following figure shows a sample of row headers and column select regions

../../_images/swipe-rows&columns.png

As noted above, swipe-select is also possible when the check box mode of Indirect Selection is used for row selection.

<script type="text/javascript">
    dojo.require("dojox.grid.EnhancedGrid");
    dojo.require("dojox.grid.enhanced.plugins.DnD");
    dojo.require("dojox.grid.enhanced.plugins.NestedSorting");
    dojo.require("dojox.data.CsvStore");

    dojo.addOnLoad(function(){
      // our test data store for this example:
      var store = new dojox.data.CsvStore({ url: '{{ dataUrl }}dojox/grid/tests/support/movies.csv' });

      // set the layout structure:
      var layout = [
          { field: 'Title', name: 'Title of Movie', width: '200px' },
          { field: 'Year', name: 'Year', width: '50px' },
          { field: 'Producer', name: 'Producer', width: 'auto' }
      ];

      // create a new grid:
      var grid = new dojox.grid.EnhancedGrid({
          query: { Title: '*' },
          store: store,
          clientSort: true,
          rowSelector: '20px',
          structure: layout,
          plugins : {dnd: true}
      }, document.createElement('div'));

      // append the new grid to the div "":
      dojo.byId("gridDiv").appendChild(grid.domNode);

      // Call startup, in order to render the grid:
      grid.startup();
    });
</script>
<div id="gridDiv" style="width: 100%; height: 100%;"></div>
<style type="text/css">
    @import "{{ baseUrl }}dojox/grid/enhanced/resources/{{ theme }}EnhancedGrid.css";
    @import "{{ baseUrl }}dojox/grid/enhanced/resources/EnhancedGrid_rtl.css";

    .dojoxGrid table {
        margin: 0;
    }

    html, body {
        width: 100%;
        height: 100%;
        margin: 0;
    }
</style>

Usage

To use this feature, you need to first enable the "DnD" plugin.

  • Declare DnD feature plugin
1
2
3
4
5
6
<script type="text/javascript">
    dojo.require("dojox.grid.EnhancedGrid");
    dojo.require("dojox.grid.enhanced.plugins.DnD");
    dojo.require("dojox.grid.enhanced.plugins.NestedSorting");//This is a must as DnD depends on NestedSorting feature
    ...
</script>
  • To use DnD feature

... with HTML markup

1
<div id="grid" store="store1" dojoType="dojox.grid.EnhancedGrid" plugins="{dnd: true}" rowSelector="20px" ... ></div>

... with JavaScript

1
var grid = new dojox.grid.EnhancedGrid({id: "grid", store: "store1", plugins: {dnd: true}, rowSelector: "20px", ...}, dojo.byId("gridDiv"));

Scenario

Selecting rows/columns via mouse clicking/keyboard

You can also select multiple non-adjacent rows/columns by holding CTRL key or select a range of adjacent rows/columns by holding SHIFT key and selecting another row. These techniques can be used with either the row headers or checkboxes for multiple row selection.

../../_images/extended-selection-checkboxes.gif
  • Selecting rows/columns by swiping.

Swiping is a useful technique for selecting multiple contiguous rows or columns.

../../_images/swipe-select.gif

Accessibility

Keyboard Support

Key Action
UP/Down arrow keys Navigate keyboard focus across row headers
Left/Right arrow keys Navigate keyboard focus across column headers
SPACE key Select a row or column
SHIFT+ Left/Right arrow keys Extend the column selection or de-selection
SHIFT + UP/Down arrow keys Extend the row selection or de-selection
  • The above key bindings are only effective when keyboard focus is in row headers or select regions of column headers.

Tips

  • When "DnD" feature is enabled but "Indirect Selection" not enabled, row selection can be handled programmatically the same way as base DataGrid:
1
2
3
for(var i = 0; i < selectedRows.length/*Array of selected row index*/; i++){
    dijit.byId('grid').selection.addToSelection(selectedRows[i]);
}
  • There are preconditions to using the "DnD" feature: * The "NestedSorting" feature must be enabled to use the "DnD" feature. * "RowSelector" should be used for "DnD", e.g.,
1
<div dojoType="dojox.grid.EnhancedGrid" plugins='{dnd: true, ...}}' rowSelector="20px" .../>
  • When the "DnD" feature is enabled, whether a column is selected can be determined by:
1
dijit.byId('grid').select.selectedColumns[columnIndex] // returns true or false , for column
  • A topic named "rowSelectionChangedTopic" will be published when row selections are changed. You can subscribe the topic as:
1
dojo.subscribe(dijit.byId('grid').rowSelectionChangedTopic, function(){...});

Drag-n-drop: rows, columns - MOVE

This feature is an enhancement to the single column moving feature of base DataGrid. Once rows or columns are selected, they can be moved to the target position by dragging them.

Note:

  • This feature is implemented as part of the "DnD" plugin of EnhancedGrid.
  • Rows and columns must be selected before being dragged.
<script type="text/javascript">
    dojo.require("dojox.grid.EnhancedGrid");
    dojo.require("dojox.grid.enhanced.plugins.DnD");
    dojo.require("dojox.grid.enhanced.plugins.NestedSorting");
    dojo.require("dojox.data.CsvStore");

    dojo.addOnLoad(function(){
      // our test data store for this example:
      var store = new dojox.data.CsvStore({ url: '{{ dataUrl }}dojox/grid/tests/support/movies.csv' });

      // set the layout structure:
      var layout = [
          { field: 'Title', name: 'Title of Movie', width: '200px' },
          { field: 'Year', name: 'Year', width: '50px' },
          { field: 'Producer', name: 'Producer', width: 'auto' }
      ];

      // create a new grid:
      var grid = new dojox.grid.EnhancedGrid({
          query: { Title: '*' },
          store: store,
          clientSort: true,
          rowSelector: '20px',
          structure: layout,
          plugins : {dnd: true}
      }, document.createElement('div'));

      // append the new grid to the div "":
      dojo.byId("gridDiv").appendChild(grid.domNode);

      // Call startup, in order to render the grid:
      grid.startup();
    });
</script>
<div id="gridDiv" style="width: 100%; height: 100%;"></div>
<style type="text/css">
    @import "{{ baseUrl }}dojox/grid/enhanced/resources/{{ theme }}EnhancedGrid.css";
    @import "{{ baseUrl }}dojox/grid/enhanced/resources/EnhancedGrid_rtl.css";

    .dojoxGrid table {
        margin: 0;
    }

    html, body {
        width: 100%;
        height: 100%;
        margin: 0;
    }
</style>

Usage

See the usage section for "Selecting rows/columns via swipe".

Scenario

  • Moving contiguous rows/columns.
../../_images/drag-contiguous-rows-and-columns.gif
  • Moving discontiguous rows/columns.

    Discontiguous rows and columns can be moved using drag-drop as well. The moved columns and rows will be adjacent, in their original relative order, after the move.

../../_images/drag-non-contiguous-rows-and-columns.gif

Accessibility

Keyboard Support

Key Action
CTRL + UP/Down arrow keys Move row(s) upward or downward by one row.
CTRL + LEFT/RIGHT arrow keys Move column(s) leftward or rightward by one column.

See also

Error in the documentation? Can’t find what you are looking for? Let us know!