如何关闭单元格编辑器?

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...

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.

Declare the common variable:-

  var lastRowId=-1;

   $(document).ready(function() {
          // put all your jQuery goodness in here.
    });
 .
 .
 .
 .

  ondblClickRow: function(rowid, iRow, iCol, e)
   {
      if(lastRowId!=-1)
         $("#jqGrid").saveRow(lastRowId, true, 'clientArray');
      $('#jqGrid').setGridParam({cellEdit: true});
      $('#jqGrid').editCell(iRow, iCol, true);
      lastRowId= rowid;

  }

After you want finish your edit

          $("#jqGrid").saveRow(jqMFPLastRowId, true, 'clientArray');




                    (or)

===========================================================================

Declare the common variable:-

  var lastRowId=-1;
  $(document).ready(function() {
          // put all your jQuery goodness in here.
    });
 .
 .
 .
 .
  ondblClickRow: function (rowid, iRow, iCol) {
        var $this = $(this);
        $this.jqGrid('setGridParam', {cellEdit: true});
        $this.jqGrid('editCell', iRow, iCol, true);
        $this.jqGrid('setGridParam', {cellEdit: false});
        lastRowId=rowid;
   },

  afterEditCell: function (rowid, cellName, cellValue, iRow) {
   if(lastRowId!=-1)
        $("#jqGrid").saveRow(lastRowId, true, 'clientArray');
}
// This worked Perfectly fine for me, hope will work for you as well.
var selectedCellId;
    var $gridTableObj = $('#jqGridTable');
    $gridTableObj.jqGrid({
        datatype : "jsonstring",
        datastr : gridJSON,
        height : ($(window).height() - 110),
        width : ($(window).width() - 80),
        gridview : true,
        loadonce : false,
        colNames : columnNames,
        colModel : columnModel,
        rowNum : gridJSON.length,
        viewrecords : true,
        subGrid : false,
        autoheight : true,
        autowidth : false,
        shrinkToFit : true,
        cellsubmit : 'clientArray',
        cellEdit : true,
        jsonReader : {
            root : "rows",
            repeatitems : false
        },
        onCellSelect : function(id, cellidx, cellvalue) { // use this event to capture edited cellID
            selectedCellId = cellidx; // save the cellId to a variable
        },
        loadComplete : function(data) {
            jQuery("tr.jqgrow:odd").addClass("oddRow");
            jQuery("tr.jqgrow:even").addClass("evenRow");
        }
    });

// Attach on click event jqgrid "saveCell" to save the cell.

var gridCellWasClicked = false;
window.parent.document.body.onclick = saveEditedCell; // attach to parent window if any
document.body.onclick = saveEditedCell; // attach to current document.
function saveEditedCell(evt) {
    var target = $(evt.target);
    var isCellClicked = $gridTableObj.find(target).length; // check if click is inside jqgrid
    if(gridCellWasClicked && !isCellClicked) // check if a valid click
        {
        var rowid = $gridTableObj.jqGrid('getGridParam', 'selrow');
    $gridTableObj.jqGrid("saveCell", rowid, selectedCellId);
    gridCellWasClicked = false;
    }
    if(isCellClicked){
        gridCellWasClicked = true; // flat to check if there is a cell been edited.
    }
};