Search code examples
javascriptjqueryajaxjquery-uijqgrid

How to close cell-editor?


Using jqGrid I want to open a cell-editor on double-click, so my code includes this part:

  ondblClickRow: function(rowid, iRow, iCol, e)
  {
    jQuery('#jqGrid').setGridParam({cellEdit: true});
    jQuery('#jqGrid').editCell(iRow, iCol, true);
    jQuery('#jqGrid').setGridParam({cellEdit: false});
  }

which works fine, but I don't know how to (auto-) close the cell-editor, when user click outside of the edit element, or press ESC, TAB, ENTER, etc...


Solution

  • The problem is that you try to implement cell editing on double-click which is not supported. Your current code don't work because if the user press Tab, Enter or Esc key the nextCell, prevCell, saveCell or restoreCell will be really called, but the methods tests internally whether cellEdit parameter is true.

    To show how to fix the problem I created the demo which uses the following code:

    cellsubmit: 'clientArray',
    ondblClickRow: function (rowid, iRow, iCol) {
        var $this = $(this);
    
        $this.jqGrid('setGridParam', {cellEdit: true});
        $this.jqGrid('editCell', iRow, iCol, true);
        $this.jqGrid('setGridParam', {cellEdit: false});
    },
    afterEditCell: function (rowid, cellName, cellValue, iRow) {
        var cellDOM = this.rows[iRow], oldKeydown,
            $cellInput = $('input, select, textarea', cellDOM),
            events = $cellInput.data('events'),
            $this = $(this);
        if (events && events.keydown && events.keydown.length) {
            oldKeydown = events.keydown[0].handler;
            $cellInput.unbind('keydown', oldKeydown);
            $cellInput.bind('keydown', function (e) {
                $this.jqGrid('setGridParam', {cellEdit: true});
                oldKeydown.call(this, e);
                $this.jqGrid('setGridParam', {cellEdit: false});
            });
        }
    }
    

    UPDATED: If you want to discard or save the last editing changes if the user click on any other cell one should extend the code with the following:

    beforeSelectRow: function (rowid, e) {
        var $this = $(this),
            $td = $(e.target).closest('td'),
            $tr = $td.closest('tr'),
            iRow = $tr[0].rowIndex,
            iCol = $.jgrid.getCellIndex($td);
    
        if (typeof lastRowIndex !== "undefined" && typeof lastColIndex !== "undefined" &&
                (iRow !== lastRowIndex || iCol !== lastColIndex)) {
            $this.jqGrid('setGridParam', {cellEdit: true});
            $this.jqGrid('restoreCell', lastRowIndex, lastColIndex, true);
            $this.jqGrid('setGridParam', {cellEdit: false});
            $(this.rows[lastRowIndex].cells[lastColIndex])
                .removeClass("ui-state-highlight");
        }
        return true;
    }
    

    The new demo shows the results.

    UPDATED 2: Alternatively you can use focusout to discard or save the last editing changes. See one more demo which use the code:

    ondblClickRow: function (rowid, iRow, iCol) {
        var $this = $(this);
    
        $this.jqGrid('setGridParam', {cellEdit: true});
        $this.jqGrid('editCell', iRow, iCol, true);
        $this.jqGrid('setGridParam', {cellEdit: false});
    },
    afterEditCell: function (rowid, cellName, cellValue, iRow, iCol) {
        var cellDOM = this.rows[iRow].cells[iCol], oldKeydown,
            $cellInput = $('input, select, textarea', cellDOM),
            events = $cellInput.data('events'),
            $this = $(this);
        if (events && events.keydown && events.keydown.length) {
            oldKeydown = events.keydown[0].handler;
            $cellInput.unbind('keydown', oldKeydown);
            $cellInput.bind('keydown', function (e) {
                $this.jqGrid('setGridParam', {cellEdit: true});
                oldKeydown.call(this, e);
                $this.jqGrid('setGridParam', {cellEdit: false});
            }).bind('focusout', function (e) {
                $this.jqGrid('setGridParam', {cellEdit: true});
                $this.jqGrid('restoreCell', iRow, iCol, true);
                $this.jqGrid('setGridParam', {cellEdit: false});
                $(cellDOM).removeClass("ui-state-highlight");
            });
        }
    }
    

    UPDATED 3: Starting with jQuery 1.8 one should use $._data($cellInput[0], 'events'); instead of $cellInput.data('events') to get the list of all events of $cellInput.