1
votes

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

1
Sorry, but it's still not full clear for me. First of all about UP and DOWN keys. What you mean with "the editable row should be switched to the upper and lower row respectively"? The changes in the current editable row (if any exist) should be saved or discarded. In general it could be dangerous to save or discard any row without any confirmation. Do you typed long comment on stackoverflow? Typing wrong key could move to another page and discard all the text typed before. One get confirmation dialog in case of writing answer on stackoverflow. It's more comfortable. - Oleg
In the same way the requirement "the cursor is at left most position in the textbox" sound very specific. There are not exist common API for all web browsers which can be used to get the caret position. Moreover keyboard support autorepeat, END and HOME buttons. There are some standards in web browser. One uses TAB and Shift-TAB to move between input fields and LEFT, RIGHT keys to move inside of one input field. You requirements seems to me can be wrong interpreted by new user of your program. - Oleg
One more remark. Editing control can be not only simple input field. On can use HTML5 Input Types like datetime, date, time and so on (see here and test in Chrome). Such inputs coantains subparts and uses LEFT and RIGHT, UP, DOWN keys to move between fields or to change the values. Try this for example. Your requirements will break the controls. - Oleg
@Oleg sorry but this is my exact requirement. My users change the data very frequently and they like to use the keyboard more instead of saving it every time with the mouse (This saves time of the user). So when the UP-DOWN key is pressed the current row being edited should be saved and the row above or below should be in editing mode. I can probably handle the validation on the server side too. I wouldn't worry too much about validation right now because my user base is my company employees itself and the app is never actually exposed to the web. - Dipen Shah
@Oleg In the same way LEFT and RIGHT keys are also required as a part of my requirement. So are you saying the caret position is impossible to get? In my current old system the users are used to the 4 navigational keys (left-right-up-down) to switch between the data to be edited. I wouldn't worry too much about the END and HOME buttons. I am aware of the standards of using web forms but my user base would not like to migrate if I can't provide the exact functionality of the old system (Its an MS Access based system). - Dipen Shah

1 Answers

1
votes

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.