Results 1 to 2 of 2

Thread: Grid.reconfigure() adds additional onspecialkey handler to cell editors

Hybrid View

Previous Post Previous Post   Next Post Next Post
    Success! Looks like we've fixed this one. According to our records the fix was applied for EXTJS-7710 in
  1. #1
    Sencha Premium Member
    Join Date
    Oct 2012
    Vote Rating

    Default Grid.reconfigure() adds additional onspecialkey handler to cell editors


    Ext version tested:

    • Ext 4.1.3 rev 548

    Browser versions tested against:

    • IE7
    • FF3.6 (firebug 1.6.2 installed)

    DOCTYPE tested against:

    • html


    • Using the cell editing plugin on a Grid, if the Grid is reconfigured with a different Store, then using the tab key when the editor is active now skips ahead two cells instead of one. Each time the Grid is reconfigured, and additional cell will be jumped over.

    Steps to reproduce the problem:

    • Using the included test case, click in a cell to activate the editor. Press the tab key and notice the cursor advances to the next cell
    • Now click the "Store 2" button in the toolbar.
    • Click a cell to activate the editor. Press the tab key and the cursor now advances two cells.

    The result that was expected:

    • tab advances 1 cell after N calls to reconfigure()

    The result that occurs instead:

    • tab advances N cells after N calls to reconfigure()

    Test Case:

    Use this modified cell-editing.js with the Cell Editing example:

        enabled: true
    Ext.Loader.setPath('Ext.ux', '../ux');
    if ('scopecss') !== -1) {
        // We are using ext-all-scoped.css, so all rendered ExtJS Components must have a
        // reset wrapper round them to provide localized CSS resetting.
        Ext.scopeResetCSS = true;
        function formatDate(value){
            return value ? Ext.Date.dateFormat(value, 'M d, Y') : '';
        Ext.define('Plant', {
            extend: '',
            fields: [
                // the 'name' below matches the tag name to read, except 'availDate'
                // which is mapped to the tag 'availability'
                {name: 'common', type: 'string'},
                {name: 'botanical', type: 'string'},
                {name: 'light'},
                {name: 'price', type: 'float'},
                // dates can be automatically converted by specifying dateFormat
                {name: 'availDate', mapping: 'availability', type: 'date', dateFormat: 'm/d/Y'},
                {name: 'indoor', type: 'bool'}
        // create the Data Stores
        var store1 = Ext.create('', {
            autoDestroy: false,
            model: 'Plant',
            data: [
                {common: 'Test1'},
                {common: 'Test2' }
            sorters: [{
                property: 'common',
        var store2 = Ext.create('', {
            autoDestroy: false,
            model: 'Plant',
            data: [
                {common: 'Test3'},
                {common: 'Test4' }
            sorters: [{
                property: 'common',
        var cellEditing = Ext.create('Ext.grid.plugin.CellEditing', {
            clicksToEdit: 1
        // create the grid and specify what field you want
        // to use for the editor at each header.
        var grid = Ext.create('Ext.grid.Panel', {
            store: store1,
            columns: [{
                id: 'common',
                header: 'Common Name',
                dataIndex: 'common',
                flex: 1,
                editor: {
                    allowBlank: false
            }, {
                header: 'Light',
                dataIndex: 'light',
                width: 130,
                editor: new Ext.form.field.ComboBox({
                    typeAhead: true,
                    triggerAction: 'all',
                    selectOnTab: true,
                    store: [
                        ['Mostly Shady','Mostly Shady'],
                        ['Sun or Shade','Sun or Shade'],
                        ['Mostly Sunny','Mostly Sunny'],
                    lazyRender: true,
                    listClass: 'x-combo-list-small'
            }, {
                header: 'Price',
                dataIndex: 'price',
                width: 70,
                align: 'right',
                renderer: 'usMoney',
                editor: {
                    xtype: 'numberfield',
                    allowBlank: false,
                    minValue: 0,
                    maxValue: 100000
            }, {
                header: 'Available',
                dataIndex: 'availDate',
                width: 95,
                renderer: formatDate,
                editor: {
                    xtype: 'datefield',
                    format: 'm/d/y',
                    minValue: '01/01/06',
                    disabledDays: [0, 6],
                    disabledDaysText: 'Plants are not available on the weekends'
            }, {
                xtype: 'checkcolumn',
                header: 'Indoor?',
                dataIndex: 'indoor',
                width: 55,
                stopSelection: false
            }, {
                xtype: 'actioncolumn',
                sortable: false,
                items: [{
                    icon: '../shared/icons/fam/delete.gif',
                    tooltip: 'Delete Plant',
                    handler: function(grid, rowIndex, colIndex) {
            selModel: {
                selType: 'cellmodel'
            renderTo: 'editor-grid',
            width: 600,
            height: 300,
            title: 'Edit Plants?',
            frame: true,
            tbar: [{
                text: 'Add Plant',
                handler : function(){
                    // Create a model instance
                    var r = Ext.create('Plant', {
                        common: 'New Plant 1',
                        light: 'Mostly Shady',
                        price: 0,
                        availDate: Ext.Date.clearTime(new Date()),
                        indoor: false
                    grid.getStore().insert(0, r);
                    cellEditing.startEditByPosition({row: 0, column: 0});
                text: 'Store1',
                handler : function(){
                    if (cellEditing.editing) {
                text: 'Store2',
                handler : function(){
                    if (cellEditing.editing) {
            plugins: [cellEditing]


    Debugging already done:

    • it looks like the Ext.form.Field objects used by the editor get an 'onspecialkey' handler added at some point in the reconfigure process--so the fields end up with N 'onspecialkey' handlers after N reconfigures, which causes the selectionModel to move over N cells. I haven't stepped through enough to find out at what point the handlers are added.

    Possible fix:

    • not provided

    Additional CSS used:

    • only default ext-all.css

    Operating System:

    • WinXP Pro

  2. #2
    Sencha Premium Member
    Join Date
    Oct 2012
    Vote Rating

    Default possible fix

    This override seems to fix it:

    Ext.define(null, {
        override: 'Ext.grid.plugin.CellEditing',
         getEditor: function(record, column) {
            var me = this,
                grid = column.up('tablepanel'),
                editors = me.editors,
                editorId = column.getItemId(),
                editor = editors.getByKey(editorId),
                listenerRemover;  // <--- new var
            // Editors are shared between editing plugins on both sides of a locked grid
            if (!editor && me.lockingPartner) {
                editor = me.lockingPartner.editors.getByKey(editorId);
            if (!editor) {
                editor = column.getEditor(record);
                if (!editor) {
                    return false;
                // Allow them to specify a CellEditor in the Column
                if (!(editor instanceof Ext.grid.CellEditor)) {
                    editor = new Ext.grid.CellEditor({
                        editorId: editorId,
                        field: editor,
                        isForTree: me.grid.isTree
                } else {
                    editor.ownerCt = me.grid;
    /* begin changes */
                listenerRemover = editor.on({
                    destroyable: true,
                    scope: me,
                    specialkey: me.onSpecialKey,
                    complete: me.onEditComplete,
                    canceledit: me.cancelEdit
                grid.on('reconfigure', listenerRemover.destroy, listenerRemover, { single: true}); 
    /* end changes */
                column.on('destroy', me.destroyEditor, me);
            editor.editingPlugin = me;
            // The Editor is a floating Component, and must be attached to an ownerCt
            // which it uses to traverse upwards to find a ZIndexManager at render time.
            editor.ownerCt = grid;
            return editor;

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts