1

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

Dipen Shah
  • 1,911
  • 10
  • 29
  • 45
  • 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 Sep 22 '15 at 13:52
  • 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 Sep 22 '15 at 13:56
  • 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](http://www.w3schools.com/html/html_form_input_types.asp) 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](http://www.w3schools.com/html/tryit.asp?filename=tryhtml_input_date) for example. Your requirements will break the controls. – Oleg Sep 22 '15 at 14:00
  • @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 Sep 22 '15 at 14:39
  • @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 Sep 22 '15 at 14:44
  • @Oleg I mostly have plain text controls all over my grid. So other HTML5 input types shouldn't really matter. Sorry my requirements seem so specific to you but this is what the user base wants. – Dipen Shah Sep 22 '15 at 14:46
  • I didn't wrote that getting the caret position is impossible, but it could be tricky. There are exist `selectionStart` property which get either the caret position inside of the `` element (if no text is selected) or the index of the beginning of selected text. So it could be not exactly what one need. There are some plugins like https://github.com/accursoft/caret which can be helpful, but I'm not sure that the plugin get you always correct caret position. About your other requirements: I understand the requirements as requirement on one *specific customer*. I don't see that as common. – Oleg Sep 22 '15 at 15:36
  • The main goal of `bindKeys` is **selection** of rows. What you want is **custom action** on pressing of some keys. So I think that you can just register `keydown` handler and implement all what you need inside of the hendler (saving or discarding currently editing row, testing whether another row exist which can be edit go on next/previous page if you want, start editing of another row and so on). – Oleg Sep 22 '15 at 15:42
  • Hello @Oleg , sorry to get back to you on this old question but I have started to implement this now. I am relatively close to what I want to achieve but I have some bugs I might need help with. First of all, here is a working demo https://jsfiddle.net/kapv1qjy/26/ . What I am trying to achieve here is when I hit the down arrow key button, what I want is that it saves the current editing row and starts editing the row immediately below the current editing row. But as you can see on the fiddle, that is not happening properly. I have two problems here: – Dipen Shah Nov 25 '16 at 15:24
  • (1) As I hit the down arrow key, you can see that the grid starts editing the row immediately below it. That is fine but the selection is still the previous one. So the currently selected row is still the old one. I have to hit the down arrow key twice to set the selection to the row below. I am not sure why its happening. Can you please help me with this? – Dipen Shah Nov 25 '16 at 15:26
  • (2) This is not happening on the demo I posted but its happening on my live code for some reason. When I hit the down arrow key, the currently editing row does not change from edit mode to normal mode. They all stay in edit mode at the same time which is not good. To explain here's a screenshot of what's happening. https://i.stack.imgur.com/AbTng.png So you can see in the image, all the rows stay in edit mode. When I see my Firebug console, the rows are getting saved and the requests are going through, but the only problem is, it does not exit the edit mode. Can you please possible help me? – Dipen Shah Nov 25 '16 at 15:29
  • I suppose that your real program works in another way because you saves the data to the server. I'd recommend you to use `aftersavefunc` callback of `saveRow` to call `editRow` of another row. In the way you will be sure that the new row will be start editing only after the previous row are saved. I recommend you to modify your code to use `list.keydown(function(e) {...});` instead of `$(document).keydown(function(e) {...});` and to move the binding inside of `$(function() {/*here*/});`. You don't need to use `list.getDataIDs()` too. `$td.closest("tr.jqgrow")` is the row, you can use `.next()` – Oleg Nov 25 '16 at 17:55
  • If I understand correctly what you try to implement then the code could be, for example, like on the modified demo https://jsfiddle.net/OlegKi/kapv1qjy/28/ – Oleg Nov 25 '16 at 19:04
  • @Oleg I have no words to thank you enough. This is exactly the behavior I wanted. Your demo works like a charm on my real program as well. The `list.keydown(function(e) {...});` idea was brilliant. I don't know why I never thought of that. – Dipen Shah Nov 25 '16 at 19:29
  • When you have some time, can you please convert your last two comments into an answer so that I can accept it so its helpful to future visitors. – Dipen Shah Nov 25 '16 at 19:30
  • Sure, I did that! I'm glad, that I could help you. You are welcome! – Oleg Nov 25 '16 at 20:02

1 Answers1

1

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.

Oleg
  • 220,925
  • 34
  • 403
  • 798