I use ExtJs GridPanel extensively both for displaying tabular information as well as for data entry. Data entry with GridPanel is mostly a pain in the neck due to navigation issues between cells.

You can use Tab/Shift+Tab for moving between adjacent cells. This works fine in ExtJs 3.x, but has issues in ExtJs 2.x and earlier. Moreover, you need to use mouse for moving between rows, and adding new rows.

So, I created a plugin for making such navigation easy. Tab/Arrow keys mostly are handled by the ExtJs framework. This plugin uses Ctrl+Arrow keys for navigation.

  • Ctrl + Left takes you to the left cell. If you are on the first cell of the row, it takes you to the last cell of previous row.
  • Ctrl + Right takes you to the right cell. If you are on the last cell of the row, it takes you to the first cell of the next row. If you are already on the last cell of the last row, it add a new row to the GridPanel, and starts editing the first cell of the new row.
  • Ctrl + Up takes you to the row above the current row.
  • Ctrl + Down takes you to the row below to the current row.

Without further discussion, here’s the javascript for the plugin.

{syntaxhighlighter brush: jscript;fontsize: 100; first-line: 1; }Rahul.ux.EditableGridPanel = function(config) {
Ext.apply(this, config);
};

// plugin code
Ext.extend(Rahul.ux.EditableGridPanel, Ext.util.Observable, {
init: function(grid) {
Ext.apply(grid, {

onRender: grid.onRender.createSequence(function(ct, position) {
var columns = this.colModel.config;
for (i = 0; i < columns.length; i++) {
if (columns[i].editor) {
columns[i].editor.addListener(‘specialkey’, this.gridEditorCtrlArrowKey, this);
}
}
}), // end of function onRender

gridEditorCtrlArrowKey: function(combo, el) {
if (el.keyCode == el.RIGHT || el.keyCode == el.LEFT || el.keyCode == el.UP || el.keyCode == el.DOWN) {
//Make sure Ctrl is pressed to avoid shifting of focus just on the Right or Left arrow key.
if (!el.ctrlKey)
return;
// } else if (el.keyCode == el.TAB) {
// if (el.shiftKey)
// return;
} else
return;

var grd = this;
var row = grd.activeEditor.row;
var col = grd.activeEditor.col;
var totalCols = grd.colModel.config.length;
var totalRows = grd.view.getRows().length;

switch (el.keyCode) {
case el.TAB:
case el.RIGHT:
var next = this.nextEditableCell(row, col);
if (next.isNew)
this.addEditableRow(grd, next.col);
else
grd.startEditing(next.row, next.col);
break;

case el.LEFT:
var prev = this.previousEditableCell(row, col);
if (prev.move)
grd.startEditing(prev.row, prev.col);
break;

case el.UP:
if (row != 0)
grd.startEditing(row – 1, col);
break;

case el.DOWN:
if (row != totalRows – 1)
grd.startEditing(row + 1, col);
break;
}

el.stopEvent();
}, // end of function gridEditorCtrlArrowKey

addEditableRow: function(grd, focusCol) {
var rowIndex = grd.addRecord();
grd.getView().focusRow(rowIndex);
grd.startEditing(rowIndex, focusCol);
},

nextEditableCell: function(row, col) {
var next = {};
for (i = col + 1; i < this.colModel.config.length; i++) {
if (!this.colModel.config[i].hidden) {
next.col = i;
break;
}
}
if (next.col != undefined) {
next.row = row;
next.isNew = false;
} else {
for (i = 0; i < this.colModel.config.length; i++) {
if (!this.colModel.config[i].hidden) {
next.col = i;
break;
}
}
next.row = row + 1;
next.isNew = true;
}

return (next);
},

previousEditableCell: function(row, col) {
var prev = {};
for (i = col – 1; i >= 0; i–) {
if (!this.colModel.config[i].hidden) {
prev.col = i;
break;
}
}
if (prev.col != undefined) {
prev.row = row;
prev.move = true;
} else if (row > 0) {
for (i = this.colModel.config.length – 1; i >= 0; i–) {
if (!this.colModel.config[i].hidden) {
prev.col = i;
prev.row = row – 1;
prev.move = true;
break;
}
}
} else {
prev.row = row;
prev.col = col;
prev.move = false;
}
return (prev);
}
});
} // end of function init
}); // end of extend{/syntaxhighlighter}

Next, if you are using Coolite 0.8.x or earlier, you can use the following server control, that would enable you to embed the above plugin in the <Plugins> inner property of <ext:GridPanel> in markup:

 

	<ToolboxItem(False)> _
	<InstanceOf(ClassName:="EditableGridPanel")> _
	Public Class EditableGridPanel
		Inherits Plugin

	End Class

 

If you are using Ext.Net 1.x or later, use the following:

{syntaxhighlighter brush: csharp;fontsize: 100; first-line: 1; }[ToolboxItem(false)]
public class EditableGridPanel:Ext.Net.Plugin
{
public override string InstanceOf
{
get
{
return “EditableGridPanel”;
}
}
}{/syntaxhighlighter}

Be sure to include the js file containing the above script in the page also.

The above scrip is flexible enough to automatically ignore columns that do not have an editor attached to them, or hidden columns.