dojox.grid.EnhancedGrid.plugins.DnD¶
Authors: | Oliver Zhu |
---|---|
Project owner: | Evan Huang |
since: | V.1.6 |
DnD plugin supports drag-and-drop of grid rows/column/cells.
Contents
Introduction¶
DnD is a plugin for dojox.grid.EnhancedGrid. It provides supports for drag-and-drop grid rows/column/cells. Users can not only move rows/columns/cells within a grid by dragging them, but also drag them out of grid to other widgets (can be another grid).
dojo.require("dojo.data.ItemFileWriteStore");
dojo.require("dijit.form.CheckBox");
dojo.require("dojox.grid.EnhancedGrid");
dojo.require("dojox.grid.enhanced.plugins.DnD");
var data = {
identifier: 'id',
label: 'id',
items: []
};
var cols = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
var data_list = [];
var i, row, j;
for(i = 0; i < 100; ++i){
row = {};
for(j = 0; j < cols.length; ++j){
row[cols[j]] = (i + 1) + cols[j];
}
data_list.push(row);
}
var len = data_list.length;
for(i = 0; i < len ; ++i){
data.items.push(dojo.mixin({ 'id': i + 1 }, data_list[i]));
}
var data1 = dojo.clone(data);
var layout1 = [{
defaultCell: {width: 3},
rows: [
{field: "A"},
{field: "B"},
{field: "C"},
{field: "D"},
{field: "E"},
{field: "F"},
{field: "G"},
{field: "H"},
{field: "I"},
{field: "J"},
{field: "K"},
{field: "L"},
{field: "M"}
]
}];
var layout2 = [{
defaultCell: {width: 3},
rows: [
{field: "N"},
{field: "O"},
{field: "P"},
{field: "Q"},
{field: "R"},
{field: "S"},
{field: "T"},
{field: "U"},
{field: "V"},
{field: "W"},
{field: "X"},
{field: "Y"},
{field: "Z"}
]
}];
function setIdentifierForNewItem(item, store, index){
var attrs = store.getIdentityAttributes(item);
for(var i = attrs.length - 1; i >= 0; --i){
item[attrs[i]] = index + (new Date()).getTime();
}
return item;
}
function setDnDConfig(gridId, type, mode, selected){
var config = {};
config[type] = {};
config[type][mode] = selected;
dijit.byId(gridId).setupDnDConfig(config);
}
function setCopyOnly(gridId, selected){
dijit.byId(gridId).dndCopyOnly(selected);
}
dojo.ready(function(){
var store1 = new dojo.data.ItemFileWriteStore({data: data});
var store2 = new dojo.data.ItemFileWriteStore({data: data1});
var grid1 = new dojox.grid.EnhancedGrid({
id: 'grid1',
store: store1,
structure: layout1,
rowSelector: '20px',
canSort: function(){return false;},
plugins: {
dnd: {
setIdentifierForNewItem: setIdentifierForNewItem,
dndConfig: {}
}
}
});
grid1.placeAt('gridContainer1');
grid1.startup();
var grid2 = new dojox.grid.EnhancedGrid({
id: 'grid2',
store: store2,
structure: layout2,
rowSelector: '20px',
canSort: function(){return false;},
plugins: {
dnd: {
setIdentifierForNewItem: setIdentifierForNewItem,
dndConfig: {}
}
}
});
grid2.placeAt('gridContainer2');
grid2.startup();
dojo.query("input.cfgbox").forEach(function(cb){
cb.checked = true;
});
dojo.query("input.copyonlyCBox").forEach(function(cb){
cb.checked = false;
});
});
<div class="myblock">
<h3>Grid 1</h3>
<div id="gridContainer1"></div>
</div>
<div class="myblock">
<h3>Grid 2</h3>
<div id="gridContainer2"></div>
</div>
<div class="myblock">
<h3>Grid 1 Configuration</h3>
<label style="font-weight: bolder;">Copy Only</label><input class="copyonlyCBox" type="checkbox" onchange="setCopyOnly('grid1', this.checked)" />
<table class="cfgtable" border="1">
<thead>
<tr>
<th>Drag</th>
<th>Within</th>
<th>In</th>
<th>Out</th>
</tr>
</thead>
<tbody>
<tr>
<td>Rows</td>
<td><input type="checkbox" class="cfgbox" onchange="setDnDConfig('grid1', 'row', 'within', this.checked)"/></td>
<td><input type="checkbox" class="cfgbox" onchange="setDnDConfig('grid1', 'row', 'in', this.checked)"/></td>
<td><input type="checkbox" class="cfgbox" onchange="setDnDConfig('grid1', 'row', 'out', this.checked)"/></td>
</tr>
<tr>
<td>Columns</td>
<td><input type="checkbox" class="cfgbox" onchange="setDnDConfig('grid1', 'col', 'within', this.checked)"/></td>
<td>Not implemented</td>
<td><input type="checkbox" class="cfgbox" onchange="setDnDConfig('grid1', 'col', 'out', this.checked)"/></td>
</tr>
<tr>
<td>Cells</td>
<td><input type="checkbox" class="cfgbox" onchange="setDnDConfig('grid1', 'cell', 'within', this.checked)"/></td>
<td><input type="checkbox" class="cfgbox" onchange="setDnDConfig('grid1', 'cell', 'in', this.checked)"/></td>
<td><input type="checkbox" class="cfgbox" onchange="setDnDConfig('grid1', 'cell', 'out', this.checked)"/></td>
</tr>
</tbody>
</table>
</div>
<div class="myblock">
<h3>Grid 2 Configuration</h3>
<label style="font-weight: bolder;">Copy Only</label><input class="copyonlyCBox" type="checkbox" onchange="setCopyOnly('grid2', this.checked)" />
<table class="cfgtable" border="1">
<thead>
<tr>
<th>Drag</th>
<th>Within</th>
<th>In</th>
<th>Out</th>
</tr>
</thead>
<tbody>
<tr>
<td>Rows</td>
<td><input type="checkbox" class="cfgbox" onchange="setDnDConfig('grid2', 'row', 'within', this.checked)"/></td>
<td><input type="checkbox" class="cfgbox" onchange="setDnDConfig('grid2', 'row', 'in', this.checked)"/></td>
<td><input type="checkbox" class="cfgbox" onchange="setDnDConfig('grid2', 'row', 'out', this.checked)"/></td>
</tr>
<tr>
<td>Columns</td>
<td><input type="checkbox" class="cfgbox" onchange="setDnDConfig('grid2', 'col', 'within', this.checked)"/></td>
<td>Not implemented</td>
<td><input type="checkbox" class="cfgbox" onchange="setDnDConfig('grid2', 'col', 'out', this.checked)"/></td>
</tr>
<tr>
<td>Cells</td>
<td><input type="checkbox" class="cfgbox" onchange="setDnDConfig('grid2', 'cell', 'within', this.checked)"/></td>
<td><input type="checkbox" class="cfgbox" onchange="setDnDConfig('grid2', 'cell', 'in', this.checked)"/></td>
<td><input type="checkbox" class="cfgbox" onchange="setDnDConfig('grid2', 'cell', 'out', this.checked)"/></td>
</tr>
</tbody>
</table>
</div>
@import "{{ baseUrl }}dojo/resources/dojo.css";
@import "{{ baseUrl }}dijit/themes/{{ theme }}/{{ theme }}.css";
@import "{{ baseUrl }}dijit/themes/{{ theme }}/document.css";
@import "{{ baseUrl }}dojox/grid/enhanced/resources/{{ theme }}/EnhancedGrid.css";
@import "{{ baseUrl }}dojox/grid/enhanced/resources/EnhancedGrid_rtl.css";
.myblock{
float: left;
margin: 5px;
margin-top: 0;
}
.cfgtable th,
.cfgtable td{
font-weight: bolder;
padding: 3px;
}
h3{
margin: 0;
}
#gridContainer1, #gridContainer2{
margin-bottom: 0px;
width: 300px;
height: 300px;
}
Configuration¶
Prerequisites¶
This DnD plugin is only available for EnhancedGrid, so use the following statement in the head of your HTML file:
dojo.require("dojox.grid.EnhancedGrid");
dojo.require("dojox.grid.enhanced.plugins.DnD");
Note that this DnD plugin is based on the Selector plugin, so there’s no need to “require” the Selector plugin anymore if you’d like to use the its functions.
Plugin Declaration¶
The declaration name of this plugin is dnd
. It is declared in the plugins
property of grid.
If your grid is created declaratively:
<div id="grid" data-dojo-type="dojox.grid.EnhancedGrid"
store="mystore" structure="mystructure"
plugins="{
dnd: /* a Boolean value or an argument object */{}
}" ></div>
If your grid is created in JavaScript:
var grid = new dojox.grid.EnhancedGrid({
id:"grid",
store:"mystore",
structure:"mystructure",
plugins:{
dnd: /* a Boolean value or an argument object */{}
}
});
As shown in the above code, you can simply set the dnd
property to true or false (disabled), or further configure it in an argument object.
The argument object can accept the following properties:
Property | Type | Default Value | Description |
---|---|---|---|
copyOnly | Boolean | false | Set whether dragging from this grid means moving or copying. |
dndConfig | Object | {} | Enable/disable dnd for every draggable objects (“row”, “col”, and “cell”) in every kind of circumstance (drag “within”, “in” to, or “out” of grid). These draggable objects and circumstances are configured in a hierarchical manner. You can set either “row”/”col”/”cell” or “within”/”in”/”out” at the first level, and configure the other group at the second level. Or simply disable/enable a whole set of situations directly at the first level. Note: 1. Circumstance (within/in/out) has higher priority than objects (row/col/cell). 2. Default value is “true”(enabled) if anything is omitted. |
Here is an example on how to set dndConfig:
GridDnD: {
dndConfig: {
// Configure in a hierarchical manner.
row: {
out: false, // This rule has lower priority, it'll be overwritten.
within: false
},
// Both orders are correct.
out: {
row: true, // This rule has higher priority, it'll be valid.
cell: false
},
// Set a whole group of situations
in: false
}
}
Currently, the following situations are supported:
DnD | within | in | out |
---|---|---|---|
col | supported | not supported | supported |
row | supported | supported | supported |
cell | supported | supported | supported |
- Note:
- Dragging columns into a grid is NOT supported currently.
- Only cells forming a rectangle are draggable (do NOT support other shapes).
Usage¶
This section shows how to DnD.
Note:
- If using Selector plugin only, the “drag” operation will start a new selection, and “drag” while pressing and holding CTRL key will start deselection.
- If using this GridDnD plugin, only drag AFTER pressing and holding CTRL key will start deselection. If you press the CTRL key DURING dragging process, it means COPY instead of MOVE.
DnD within Grid¶
If enabled, selected rows/columns/cells can be dragged within grid.
Dragging Columns
Dragging Rows
Dragging Cells
DnD across Grids¶
If both grids are EnhancedGrid with this GridDnD plugin, and one has enabled dragging “out” while the other enabled dragging “in”, data can be dragged across grids. Note: Dragging columns across grids is not supported.
Moving rows across grids
Copy rows across grids
Moving cells across grids
Copy cells across grids
If selected cells do not form a rectangle, they can not be dragged:
Because the grid lazy loads store data, and extended selection is supported, it is possible to select rows or cells that are not loaded to the client side yet. If this situation occurs, it’s not allowed to “drop” these unloaded objects to another grid:
DnD from Grid to Other Widgets¶
Other widgets/dom nodes can accept dragged data from a grid by extending dojox.grid.enhanced.plugins.GridSource instead of dojo.dnd.Source.
GridSource extends dojo.dnd.Source. Its “accept” property can support “grid/cols”, “grid/rows”, and “grid/cells”.
GridSource provides the following events to handle grid related dnd:
- onDropGridColumns(grid, columnIndexes):
- When a set of grid columns is dragged to this source.
Arguments | Type | Description |
---|---|---|
grid | dojox.grid.EnhancedGrid | The source grid. |
columnIndexes | Integer[] | The indexes of the dragged columns |
- onDropGridRows(grid, rowIndexes):
- When a set of grid rows is dragged to this source.
Arguments | Type | Description |
---|---|---|
grid | dojox.grid.EnhancedGrid | The source grid. |
rowIndexes | Integer[] | The indexes of the dragged rows |
- onDropGridCells(grid, leftTopPoint, rightBottomPoint):
- When a block of grid cells is dragged to this source.
Arguments | Type | Description |
---|---|---|
grid | dojox.grid.EnhancedGrid | The source grid. |
leftTopPoint | Object(__SelectCellItem) | The left-top cell of the selected cells. (For RTL, it’s the right-top cell) |
rightBottomPoint | Object(__SelectCellItem) | The right-bottom cell of the selected cells. (For RTL, it’s the left-top cell) |
The following example shows how to use these events to drag a grid row to a form.
The HTML is:
<div id="grid" data-dojo-type="dojox.grid.EnhancedGrid" store="test_store" structure="layout" rowSelector="20px"
plugins="{
dnd: {copyOnly: true}
}"
></div>
<form id="songForm" class="container">
<table>
<tr>
<td><label for="inputName">Song name</label></td>
<td><input id="inputName" type="text" /></td>
</tr>
<tr>
<td><label for="inputAuthor">Artist</label></td>
<td><input id="inputAuthor" type="text" /></td>
</tr>
<tr>
<td><label for="inputAlbum">Album</label></td>
<td><input id="inputAlbum" type="text" /></td>
</tr>
</table>
</form>
The JavaScript code is:
dojo.require("dojox.grid.enhanced.plugins.GridSource");
dojo.ready(function(){
var formTarget = new dojox.grid.enhanced.plugins.GridSource(dojo.byId("songForm"),{
isSource: false,
insertNodesForGrid: false
});
dojo.connect(formTarget, "onDropGridRows", function(grid, rowIndexes){
var s = grid.store,
row = rowIndexes[0];
dojo.attr(dojo.byId("inputName"), "value", s.getValue(grid.getItem(row), "Name"));
dojo.attr(dojo.byId("inputAuthor"), "value", s.getValue(grid.getItem(row), "Artist"));
dojo.attr(dojo.byId("inputAlbum"), "value", s.getValue(grid.getItem(row), "Album"));
});
});
And here is the effect:
Public Methods¶
- copyOnly(isCopyOnly):
- Get/set function of the copyOnly property in the argument object.
Arguments | Type | Optional/Mandatory | Description |
---|---|---|---|
isCopyOnly | Boolean | Optional(default to undefined) | Whether DnD is a copy operation or a move operation. If omitted, this is a getter. |
[return] | Boolean|Undefined | If isCopyOnly is undefined, return the copyOnly property of this plugin. |
- setupConfig(config):
- Change the dndConfig property in the argument object.
Arguments | Type | Optional/Mandatory | Description |
---|---|---|---|
config | Object | Mandatory | Same as dndConfig. |
Known Limitations¶
- Multiple row layout is not supported by this DnD plugin.
- Please be careful when dragging a numeric cell to a string cell (or vice versa), since sorting will have problems after that. This is because comparing string value and number value always returns false.
See Also¶
- dojox.grid.DataGrid - The base grid
- dojox.grid.EnhancedGrid - The enhanced grid supporting plugins
- dojox.grid.EnhancedGrid.plugins - Overview of the plugins of enhanced grid
- dojox.grid.EnhancedGrid.plugins.Selector - The selector plugin of enhanced grid
- dojox.grid.TreeGrid - Grid with collapsible rows and model-based (dijit.tree.ForestStoreModel) structure