Dipen Shah Dipen Shah - 13 days ago 16
HTML Question

jqGrid - bindkeys change arrow and tab keys behavior

I would like to provide

bindKeys
functionality on my jqGrid. This means on Enter, the data should be saved (working fine), on left arrow the cursor should move to the left editable cell and so on.

enter image description here

This means when the cursor is at left most position in the textbox as shown in the image and the left arrow key is pressed, the cursor should be moved to the previous editable cell (in this case Item Number). If the cursor is somewhere in the middle of the text then the normal behavior should be happening.

Similarly on the right arrow key, it should move to the right editable cell, if the cursor is at the right most position. Again if the cursor is somewhere in the middle of the text then the normal behavior should be happening.

On the up and down arrow keys, the editable row should be switched to the upper and lower row respectively.

I have tried implementing
bindKeys
but it does not seem to work. What am I missing here?

Grid code: jsFiddle

Answer

I would suggest you to modify your demo https://jsfiddle.net/kapv1qjy/26/ to something like https://jsfiddle.net/OlegKi/kapv1qjy/28/, which uses modified keydown event handler:

list.keydown(function(e) {
  switch (e.which) {
    case 40: // down
      var $grid = $(this),
        $td = $(e.target).closest("tr.jqgrow>td"),
        $tr = $td.closest("tr.jqgrow"),//$td.parent()
        rowid = $tr.attr("id"),
        $trNext = $tr.next("tr.jqgrow"),
        p = $grid.jqGrid("getGridParam"),
        cm = $td.length > 0 ? p.colModel[$td[0].cellIndex] : null;
      var cmName = cm !== null && cm.editable ? cm.name : 'PackCartonNo';
      var selectedRowId = $grid.jqGrid('getGridParam', 'selrow');
      if (selectedRowId == null || rowid !== selectedRowId) { return; }

      // this is the DOM of table and $tr[0] is DOM of tr
      if ($trNext.length < 1) { return; }

      var rowidNext = $trNext.attr("id");
      $grid.jqGrid('saveRow', rowid, {
        aftersavefunc: function () {
          $(this).jqGrid("setSelection", rowidNext, false)
            .jqGrid("editRow", rowidNext, {
              keys: true,
              focusField: cmName
            });
        }
      });

      e.preventDefault();
      break;

    default:
      return;
  }
});

I'd recommend you in general to use relative addressing of elements inside of event handler. e.target is the target DOM of the event, which is typically somewhere inside of some <td> element. By usage var $td = $(e.target).closest("tr.jqgrow>td") and var $tr = $td.closest("tr.jqgrow") you can "travel" up to the the <td> and <tr> elements, which contains e.target. In the same way you can use var $trNext = $tr.next("tr.jqgrow"), to get the next data row (and $tr.prev("tr.jqgrow") to get the previous one). The implementation of jQuery methods uses native DOM methods, which works very quickly. On the other side list.getDataIDs() goes over all elements of the grid and saves the values of id attributes of all the elements in an array. It works more slowly.

Finally you should calls setSelection and editRow on the next row only after the previous row is successfully saved. You should stay editing on the current row in case of any server side errors, for example, (because of validation errors, for example). Moreover placing of the calls of the methods inside of aftersavefunc makes us sure that we will not edit multiple rows at the same time.