3

How to start inline edit if Enter is pressed in jqGrid and multiselect: true option is also used? If multiselct is present, jqGrid bindKeys function does not have any effect.

To verify this testcase below can be used (based on sample provided in Oleg comment).

Steps to reproduce:

  1. Save code below to html file and open it in IE 9
  2. Click in grid and press enter

Observed:

  1. Message box does not appear
  2. Also up and down arrow move whole grid

Expected:

  1. Enter press should cause message box to appear
  2. up and down arrow should change current row in grid

How to get expected behaviour ?

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>http://stackoverflow.com/questions/5988767/highlight-error-cell-or-input-when-validation-fails-in-jqgrid</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    <link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/themes/redmond/jquery-ui.css" />
    <link rel="stylesheet" type="text/css" href="http://www.ok-soft-gmbh.com/jqGrid/jquery.jqGrid-4.0.0/css/ui.jqgrid.css" />
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js"></script>
    <script type="text/javascript" src="http://www.ok-soft-gmbh.com/jqGrid/jquery.jqGrid-4.0.0/js/i18n/grid.locale-en.js"></script>
    <script type="text/javascript">
        $.jgrid.no_legacy_api = true;
        $.jgrid.useJSON = true;
    </script>
    <script type="text/javascript" src="http://www.ok-soft-gmbh.com/jqGrid/jquery.jqGrid-4.0.0/js/jquery.jqGrid.min.js"></script>
    <script type="text/javascript">
        $(function () {
            var mydata = [
                    { id: "1", invdate: "2007-10-01", name: "test", note: "note", amount: "200.00", tax: "10.00", closed: true, ship_via: "TN", total: "210.00" },
                    { id: "2", invdate: "2007-10-02", name: "test2", note: "note2", amount: "300.00", tax: "20.00", closed: false, ship_via: "FE", total: "320.00" },
                    { id: "3", invdate: "2007-09-01", name: "test3", note: "note3", amount: "400.00", tax: "30.00", closed: false, ship_via: "FE", total: "430.00" },
                    { id: "4", invdate: "2007-10-04", name: "test4", note: "note4", amount: "200.00", tax: "10.00", closed: true, ship_via: "TN", total: "210.00" },
                    { id: "5", invdate: "2007-10-31", name: "test5", note: "note5", amount: "300.00", tax: "20.00", closed: false, ship_via: "FE", total: "320.00" },
                    { id: "12", invdate: "2007-09-10", name: "test12", note: "note12", amount: "500.00", tax: "30.00", closed: false, ship_via: "FE", total: "530.00" }
                ];

            var grid = $("#grid");
            grid.jqGrid({
                datatype: 'local',
                data: mydata,
                colModel: [
                    { name: 'invdate', editable: true, width: 30 },
                    { name: 'name', editable: true, width: 271 }
                ],
                gridview: true,
                pager: '#pager',
                viewrecords: true,
                multikey: "ctrlKey",  // added July 6, 2011
                scroll:1,  // added July 6, 2011 todo: data should passed from URL
                multiselect: true,
                multiboxonly: true,
                editurl: 'clientArray'
            });

        $("#grid").jqGrid('bindKeys', {
            onEnter: function (rowid) {
                alert("You enter a row with id: " + rowid);
            }
        });
      });
    </script>
</head>
<body>
        <table id="grid"></table>
        <div id="pager"></div>
</body>
</html>

UPDATE: added multiboxonly: true to testcase do demontrate previous row not unselected issue

Update

Added multikey: "ctrlKey" to testcase. In this case bindKeys proposed in Oleg answer stops working

Andrus
  • 26,339
  • 60
  • 204
  • 378
  • To format the code you should select the code and click "{}" button in the editing toolbar. It will select 4 spaces at the beginning of every line of code and the code will good already good formated. Moreover I wrote you before that you should place call of `$("#grid").jqGrid('bindKeys'...});` **inside** of the `$(function () {/*here*/});`. See description of `$(document).ready` [here](http://api.jquery.com/ready/). – Oleg May 31 '11 at 12:44

1 Answers1

5

The code which you posted should work. Probably you use it on the wrong place.

The only thing which you should take in the consideration that after the end of the row editing the focus is lost and you can't use arrows to move th the next row. You should use aftersavefunc parameter of the editRow method to restore the grid focus:

var grid = $('#grid');
grid.jqGrid('editRow',rowid,true,null, null, null, {},function(){
    setTimeout(function(){
        grid.focus();
    },100);
});

The demo is the small modification of the demo from the answer. You can use keyboard to move the row selection and enter to start inline editing and to save the row.

UPDATED: I ask you always to append your original question with additional information instead of full rewriting of the question. Your original question don't contained anything about the usage of multiselect: true. This case (multiselect: false) and my first demo could be interesting for other users. So the general practice is to append the original question with "UPDATED:" part or just ask a new question. Currently if somebody will read your question and my answer he/she will wonder: "what a queer answer? Probably the answer not carefully read the question.".

Now about your current problem in case of multiselect: true. How you know jqGrid 4.0.0 is the first version which has support of keyboard navigation in the grid and treegrid and which has bindKeys method. The solution is far from be perfect. Many actions can't be done with the keyboard. For example the buttons in the navigation toolbar ("Add", "Edit", "Delete" etc) could be not clicked with respect of keyboard. To use keyboard navigation in the jqGrid many places of jqGrid code are extended with the setting of tabindex attribute. For example in the line the selected row (<tr> element) receive the attribute tabindex="0", but the line works only in case of multiselect: false. In the line of bindKeys code will be search (and not found) the attribute tabindex="0". So the current implementation of bindKeys don't work in the multiselect: true mode.

As I wrote before the full support of multiselect: true mode can be implemented only with many changes in the jqGrid code. As a workaround I could suggest the following: we can overwrite the code of bindKeys method only with the changed implementation.

The corresponding demo you can find here. The JavaScript code form the demo is:

$.extend($.fn.jqGrid,{
    bindKeys : function( settings ){
       'use strict';
        var o = $.extend({
            onEnter: null,
            onSpace: null,
            onLeftKey: null,
            onRightKey: null,
            scrollingRows : true
        },settings || {});
        return this.each(function(){
            var $t = this;
            if( !$('body').is('[role]') ){$('body').attr('role','application');}
            $t.p.scrollrows = o.scrollingRows;
            $($t).keydown(function(event){
                var target = $($t).find('tr[tabindex=0]')[0], id, mind, r,
                expanded = $t.p.treeReader.expanded_field;
                if (!target && $t.p.selrow !== null) {
                    target = $t.rows.namedItem($t.p.selrow);
                }
                //check for arrow keys
                if(target) {
                    mind = $t.p._index[target.id];
                    if(event.keyCode === 37 || event.keyCode === 38 || event.keyCode === 39 || event.keyCode === 40){
                        // up key
                        if(event.keyCode === 38 ){
                            r = target.previousSibling;
                            id = "";
                            if(r) {
                                if($(r).is(":hidden")) {
                                    while(r) {
                                        r = r.previousSibling;
                                        if(!$(r).is(":hidden") && $(r).hasClass('jqgrow')) {id = r.id;break;}
                                    }
                                } else {
                                    id = r.id;
                                }
                            }
                            if ($.inArray(id,$t.p.selarrrow) === -1) {
                                $($t).jqGrid('setSelection', id);
                            } else {
                                $t.p.selrow = id;
                            }
                        }
                        //if key is down arrow
                        if(event.keyCode === 40){
                            r = target.nextSibling;
                            id ="";
                            if(r) {
                                if($(r).is(":hidden")) {
                                    while(r) {
                                        r = r.nextSibling;
                                        if(!$(r).is(":hidden") && $(r).hasClass('jqgrow') ) {id = r.id;break;}
                                    }
                                } else {
                                    id = r.id;
                                }
                            }
                            if ($.inArray(id,$t.p.selarrrow) === -1) {
                                $($t).jqGrid('setSelection', id);
                            } else {
                                $t.p.selrow = id;
                            }
                        }
                        // left
                        if(event.keyCode === 37 ){
                            if($t.p.treeGrid && $t.p.data[mind][expanded]) {
                                $(target).find("div.treeclick").trigger('click');
                            }
                            if($.isFunction(o.onLeftKey)) {
                                o.onLeftKey.call($t, $t.p.selrow);
                        }
                        }
                        // right
                        if(event.keyCode === 39 ){
                            if($t.p.treeGrid && !$t.p.data[mind][expanded]) {
                                $(target).find("div.treeclick").trigger('click');
                            }
                            if($.isFunction(o.onRightKey)) {
                                o.onRightKey.call($t, $t.p.selrow);
                        }
                        }
                        return false;
                    }
                    //check if enter was pressed on a grid or treegrid node
                    else if( event.keyCode === 13 ){
                        if($.isFunction(o.onEnter)) {
                            o.onEnter.call($t, $t.p.selrow);
                        }
                        return false;
                    } else if(event.keyCode === 32) {
                        if($.isFunction(o.onSpace)) {
                            o.onSpace.call($t, $t.p.selrow);
                        }
                        return false;
                    }
                }
            });
        });
    }
});

and

var grid = $("#list");
...

grid.jqGrid('bindKeys', {
    onEnter: function(rowid) {
        //alert("You enter a row with id: " + rowid);
        editingRowId = rowid; // probably cab be replaced to grid[0].p.selrow
        // we use aftersavefunc to restore focus
        grid.jqGrid('editRow',rowid,true,null, null, null, {},function(){
            setTimeout(function(){
                grid.focus();
            },100);
        });
    },
    onSpace: function(rowid) {
        grid.jqGrid('setSelection', rowid);
    }
});

// select one row at the begining and set the focus
grid.jqGrid('setSelection',"1");
grid.focus();

I repeat one more time that I find the code which I posted not perfect. One should make visible which line have focus and make much more things. I wanted only to show which kind of changes and where should be done to allow keyboard navigation for the musliselect grids.

Edit

If multikey:"ctrlKey" is added bindKeys. Code in answer does not work. Also using setFocus in answer code causes focus to jump to another row after editing, so this should removed. There is no way to set focus after editing to current row, mouse clik is always required, jqGrid does not support inline edit using keyboard only.

Community
  • 1
  • 1
Oleg
  • 220,925
  • 34
  • 403
  • 798
  • @Oleg: I modified question to include complete standalone testcase based on Oleg demo. Problem persists even if using code based on this sample. – Andrus May 30 '11 at 15:16
  • 1
    @Andrus: You placed the `$("#grid").jqGrid('bindKeys', {...});` **outside of** the block `$(function () {...});`. You should place it inside to make it working. – Oleg May 30 '11 at 15:43
  • @Oleg: I changed testcase to add bindKey inside ready function and added multiselect: true. multiselect causes the issue how to fix it ? – Andrus May 30 '11 at 16:27
  • 1
    @Andrus: `bindKeys` doesn't support the `multiselect:true` mode. It uses `tabindex="0"` attribute of `` (see [here](https://github.com/tonytomov/jqGrid/blob/v4.0.0/js/grid.base.js#L3173)). On the other side the attribute will be [set](https://github.com/tonytomov/jqGrid/blob/v4.0.0/js/grid.base.js#L2484) only in case of [multiselect:true](https://github.com/tonytomov/jqGrid/blob/v4.0.0/js/grid.base.js#L2480). – Oleg May 30 '11 at 18:08
  • @Oleg: In jqGrid we need to allow users to select multiple rows for delete and also also to edit data using enter. How to solve this? – Andrus May 31 '11 at 06:42
  • @Oleg: Thank you very much for answer and hard work on jqGrid support. I changed question text and testcase to state that question is about invoking inline editing by enter **if multiselect is active jqGrid** . I'm sorry but there is no answer for this. It is possible to change controller to generate dummy checkbox first column. In this case there is no multiselect needed. However I don't know how to implement delete command in this case. Pressing delete button should determine checked row ids and pass them to server method. No idea how to implement this. – Andrus May 31 '11 at 10:06
  • @Oleg: Thank you very much for multiselect issue solution. In your sample I changed `id:"2"` to `id:"%5c%3cFail"` In this case Enter does not start editing in this row. How to allow urlencoded row ids like `%5c%3cFail` ? Another issue: up and down arrows do not clear highlight from previous row. I added `multiboxonly: true` but problem persists. How to make only current row highlighted on up/down arrows? – Andrus May 31 '11 at 15:48
  • 1
    @Andrus: The usage of special characters such as `!"#$%&'()*+,./:;<=>?@[\]^``{|}~` is **very bad**! You can easy fix the problem in the demo by escaping '%' and other special characters. To do this you should replace the line `r = $("#"+$t.p.selrow);` with something like `r = $("#"+$t.p.selrow.replace(/([\.\%\!\$\&\:\[\]])/g,"\\$1"));` (I don't included the full list of special characters). See [the modified demo](http://www.ok-soft-gmbh.com/jqGrid/SimpleLocalGridWithInlineEditingOnEnterMultiselect1.htm). How many places there are in jqGrid or other code? – Oleg Jun 01 '11 at 08:17
  • @Andrus: Read [here](http://api.jquery.com/category/selectors/) and [here](http://docs.jquery.com/Frequently_Asked_Questions#How_do_I_select_an_element_by_an_ID_that_has_characters_used_in_CSS_notation.3F) about escaping of special characters. – Oleg Jun 01 '11 at 08:19
  • @Andrus: About the unselecting of the rows on up and down arrows. I don't think that it would be correct behavior. It you have cler imagination how it should work you should modify the code of `bindKeys` yourself corresponds to your imagination. I showed you the way how you can do this. – Oleg Jun 01 '11 at 08:22
  • @Oleg: Thank you. Removing special characters from row ids solves first issue. I added `multiboxonly: true` to the testcase. In this case up and down arrows should highlight current row only. Overridden bindKeys method still hightlights multiple rows. How to change this so that moving next/previous row highlights only this row ? What exactly needs changed in this method? – Andrus Jun 01 '11 at 14:30
  • @Andrus: you should examine the code of `bindKeys`. You will find many places where `'setSelection'` are used. You should change the code `bindKeys` how you as want. First of all you should define exactly what you want and then implement this in the JavaScript code. – Oleg Jun 01 '11 at 15:02
  • @Oleg: Thank you. I added resetSelection() calls before `$($t).jqGrid('setSelection', id);` lines. This seems to work. I marked your answer as answer to this and also flagged some of your comments as great. – Andrus Jun 01 '11 at 17:24
  • @Andrus: You are welcome! You should understand another important right which you has starting with 15 reputation points: voting of answers and questions. [Here](http://stackoverflow.com/faq#howtoask) you can read the simple rule: *"As you see new answers to your question, vote up the helpful ones by clicking the upward pointing arrow to the left of the answer"*. I recommend you to use voting not only helpful answers on your question, but **all helpful questions or answers** which you find. If you vote one answer other people could better find it because of algorithms of the searching engine. – Oleg Jun 01 '11 at 17:35
  • @Oleg: I clicked in this arrow. Tooltip in this arrow tells that this means "great comment". So it looks like voting up and great comment flagging are the same things. – Andrus Jun 03 '11 at 07:21
  • @Andrus: There are the arrow about **the answer** and not only about **the comment** to the answer. The main criteria for the searching engine is the voting of the answer. If you don't find the correct place - forget it. You will find it out sometime later. – Oleg Jun 03 '11 at 07:32
  • @Andrus: I updated some demos to use `tableDOM.rows.namedItem` method instead of `$("#"...)` jQuery selector. Additionally I posted [the bugfix](http://www.trirand.com/blog/?page_id=393/bugs/more-meta-characters-supported-by-jqid/#p23489) in the `jqID` method of jqGrid. I continue strictly recommend you don't use special characters in the ids. Instead of that extending of your current database with additional INT IDENTITY column and setting UNIQUE constraint on the column will not break your existing application, but gives one more data id which you can use in jqGrid. – Oleg Jun 06 '11 at 13:32
  • @Oleg: thank you again. I refactored test so that it uses only alphanumeric rowIds. I added also `multikey: "ctrlKey"` to fix row selection issue if scroll:1 is used. After that your binKeys method in answer stops working. This can reproduced in the test url which I sent to you. Also, using setFocus in your sample causes focus to switch to other row if editing is completed. So this cannot used, no way to set focus to row after editing. Should I modify the question by adding that `multikey:"ctrlKey"` is also used and un-mark answer since this is not answered? – Andrus Jun 06 '11 at 14:52