ExtJS 4: Excel-style keyboard navigation in an editable Grid

datagrid, extjs, extjs4

Solution

something like this ??? when editing try using `tab`, `shift + tab`, `enter`, and `shift + enter`

what i did is override the `cellediting` and `selection.rowmodel`

actually, i have had a similar question with you. and @Lionel Chan help me solve it. and my solution above is base on his idea.

Note : only work with Extjs 4.0.7

EDIT (if my jsfiddle broken, here's the override)

Ext.override(Ext.grid.plugin.CellEditing,{
    onSpecialKey: function(ed, field, e) {
        var grid = this.grid,sm;
        if (e.getKey() === e.TAB) {
            e.stopEvent();
            sm = grid.getSelectionModel();
            if (sm.onEditorTab)sm.onEditorTab(this, e);
        }else if(e.getKey() === e.ENTER){
            e.stopEvent();
            sm = grid.getSelectionModel();
            if (sm.onEditorEnter)sm.onEditorEnter(this, e);
        }
    }
});

Ext.override(Ext.selection.RowModel, {
    lastId:null,
    onEditorTab: function(ep, e) {
        var me = this,
            view = me.view,
            record = ep.getActiveRecord(),
            header = ep.getActiveColumn(),
            position = view.getPosition(record, header),
            direction = e.shiftKey ? 'left' : 'right',
            newPosition = view.walkCells(position, direction, e, false),
            newId=newPosition.row,
            grid=view.up('gridpanel');

        if (me.lastId!=newId && me.lastId!=null){
            deltaX = me.lastId<newId? -Infinity : Infinity;
            header=grid.headerCt.getHeaderAtIndex(newPosition.column);
            if(header){
                while(!header.getEditor()){
                    newPosition= view.walkCells(newPosition,direction, e, false);
                    header=grid.headerCt.getHeaderAtIndex(newPosition.column);
                }
            }
        }else{
            deltaX = ep.context.column.width * (direction== 'right' ? 1 : -1);
        }
        grid.scrollByDeltaX(deltaX);
        me.lastId=newPosition.row;
        Ext.defer(function(){
            if (newPosition)ep.startEditByPosition(newPosition);
            else ep.completeEdit();
        }, 100);
    },
    onEditorEnter:function(ep,e){
        var me = this,
            view = me.view,
            record = ep.getActiveRecord(),
            header = ep.getActiveColumn(),
            position = view.getPosition(record, header),
            direction = e.shiftKey ? 'up' : 'down',
            newPosition = view.walkCells(position, direction, e, false),
            newId=newPosition.row,
            grid=view.up('gridpanel');

        deltaY=20 * (direction== 'down' ? 1 : -1);
        grid.scrollByDeltaY(deltaY);
        me.lastId=newPosition.row;
        Ext.defer(function(){
            if (newPosition)ep.startEditByPosition(newPosition);
            else ep.completeEdit();
        }, 100);
    }
});

Problem

Using ExtJS 4 I would like to create a grid into which the user will enter a long list of numbers. I would like the user to be able to finish editing one cell by pressing "Enter" and then automatically move to the cell below and start editing. Ext.grid.plugin.CellEditing seems to work well for the purpose of editing, but I can't find a way to detect and handle the keyUp event. I tried approaching the matter using the "edit" event with this code: ``` selType: 'cellmodel', plugins: [ Ext.create('Ext.grid.plugin.CellEditing', { clicksToEdit: 1, listeners: { edit: function (editor, e, eOpts) { // If the event is fired by pressing "Enter", the column and row associated with event will // be the same as the currently selected row and column if (e.grid.selModel.position.column == e.colIdx && e.grid.selModel.position.row == e.rowIdx){ // Check if we are in the final row if (e.rowIdx+1 == e.grid.getStore().getTotalCount()){ return true; } editor.startEditByPosition({row: e.rowIdx+1, column: e.colIdx}); return false; } } } }) ], ``` The problem with this approach is that if the user starts editing the cell, then clicks on a GUI element outside of the Grid, the edit event does not distinguish this from the "Enter" key being pressed. Can this be fixed? Perhaps I should be trying to implement a custom SelectionModel instead? How does one go about starting with that approach?

Original source