Andrus
Andrus

Reputation: 27921

How to set focus to autocomplete contents on inline edit in free jqgrid

Free jqgrid first column is Jquery UI autocomplete using custom edit type. Field is made focusable using focusField: true

$.extend(true,$.jgrid.inlineEdit, {
    position: "beforeSelected",
    focusField: true,
    keys: true } );

If inline editing is started, jqgrid puts focus to autocomplete dropdown button. How to fix this that focus is put to autocomplete input element ?

Autocomplete button is defined with tabindex=-1:

<button type='button' class='btn btn-default btn-form-dropdown' tabindex=-1 aria-label='Open menu'>
<span class='caret'></span></button>

It does not receive focus if tab key is pressed in inline edit.

jqgrid code contains:

    getFocusable = function (elem) {
        return $(elem).find("input,textarea,select,button,object,*[tabindex]")
                                            .filter(":input:visible:not(:disabled)");
                                },

So jqgrid puts focus to element even if it contains tabindex=-1

How to fix this ?

Posted also in https://github.com/free-jqgrid/jqGrid/issues/186

Update

Steps to reproduce the issue:

  1. Open page below in Chrome
  2. Select row
  3. Click in inline edit button

Observed:

Button receives focus

Expected:

input element should receive focus

Code to reproduce:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/redmond/jquery-ui.css" />
    <link rel="stylesheet" href="http://rawgit.com/free-jqgrid/jqGrid/master/css/ui.jqgrid.css" type="text/css" />
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.js"></script>
    <script src="http://rawgit.com/free-jqgrid/jqGrid/master/js/jquery.jqgrid.src.js"></script>
    <script>
        $(document).ready(function () {
            var mydata = [
                { id: 0, Name: "Indiana", Category: "IN" },
                { id: 1, Name: "California", Category: "CA" },
                { id: 2, Name: "Pennsylvania", Category: "PA" },
                { id: 3, Name: "Texas", Category: "TX" }
            ];
            var lastSel;
            var grid = $("#list");

            grid.jqGrid({
                data: mydata,
                datatype: 'local',
                colModel: [
                    {
                        name: 'Name', editable: true, width: 200,
                        edittype: 'custom',
                        editoptions: {
                            custom_element: combobox_element,
                            custom_value: function (elem) {
                                return elem.find("input").val();
                            }
                        }
                    },

                { name: 'Category', index: 'Category', width: 50, editable: true }
                ],
                ignoreCase: true,
                gridview: true,
                viewrecords: true,
                rownumbers: true,
                pager: '#pager',
                editurl: 'clientArray',
                ondblClickRow: function (id, ri, ci) {
                    grid.jqGrid('editRow', id, true, null, null, 'clientArray', {});
                },
                onSelectRow: function (id) {
                    if (id && id !== lastSel) {
                        if (typeof lastSel !== "undefined") {
                            grid.jqGrid('restoreRow', lastSel);
                        }
                        lastSel = id;
                    }
                }
            }).
            jqGrid("inlineNav", '#pager');
        });

        var getColumnByName = function (grid, columnName) {
            var cm = grid.jqGrid('getGridParam', 'colModel'), i = 0, l = cm.length;
            for (; i < l; ++i) {
                if (cm[i].name === columnName) {
                    return cm[i];
                }
            }
            return null;
        };

        function combobox_element(value, options) {
            var elemStr = '<div><input class="FormElement', newel, width;
            if (options.id === options.name) {
                elemStr += '" size="' +
                        options.size + '"' + ' id="' + options.id + '"';
            }
            else {
                elemStr += ' form-control jqgrid-inlineedit-autocomplete" ' +
                   ' style="width:' + width + 'px" ' + ' id="' + options.id + '_x"';
            }
            elemStr += ' value="' + value + '" lookup="' + options.lookup + '"/>';
            elemStr += "<button type='button' class='btn btn-default btn-form-dropdown' tabindex=-1 aria-label='Open menu'>" +
        "<span class='caret'></span></button>";
            elemStr += '</div>';
            newel = $(elemStr)[0];
            setTimeout(function () {
                input_autocomplete(newel);
            }, 50);
            return newel;
        }

        function input_autocomplete(newel) {
            var input = $("input", newel);
            input.autocomplete({
                source: ["Indiana", 
                "California",
                "Pennsylvania"
                ]
            }
           );
            $("button", newel)
            .bind({
                click: function () {
                    input.focus();
                }
            });
        }
    </script>
</head>

<body>
    <table id="list"></table>
    <div id="pager"></div>
</body>
</html>

Upvotes: 0

Views: 1472

Answers (1)

Oleg
Oleg

Reputation: 221997

I'm not sure what you do exactly. Which part of your code place <button type='button' ... tabindex=-1 ...?

Placing of tabindex=-1 means only that the field should not get focus if the user press Tab or Shift-Tab, but it means that the field should do can be focusable via API call. In other wards, the existence of tabindex make it focusable, but the negative value of tabindex informs to exclude the element from sequential focus navigation only. W3 standard formulate it as (see here)

The user agent must set the element's tabindex focus flag, but should not allow the element to be reached using sequential focus navigation.

One should remove tabindex attribute if one don't want to make the button be focusable.

If you don't create the attribute and it does some control which you use, but you still don't want to set the focus on <button>, then you can just set the focus on another editable column. You can use focusField: "someColumnName" or focusField: indexOfSomeColumn to set the focus on specific column.

UPDATED: I posted the fix which adds the usage of .first() before call of .focus(). After the changes the demo which you posted works good.

Upvotes: 1

Related Questions