Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set tabindex in vertical order of columns

I am assigning tabindex for my input type text, and which are not disabled/hidden. The following is what I tried, and it works. However, The order of indexes are horizontally assigned in the table. I would need the order of tabindex in column wise rather than horizontal. Any suggestions how to achieve that ? I want the order to be as follow This Q is a follow up to this enter key to follow the tabindex (in scenario where enter key is changed to behave as tab).

   col1 col2 col3
    1      3    7
    2      4    8
           5    9 
           6   10  

(":input:not([disabled]):not(:hidden)").not($(":submit")).not($(":reset")).each(function (i) { $(this).attr('tabindex', i + 1); })
like image 1000
user5249203 Avatar asked Jul 25 '16 19:07

user5249203


People also ask

How do I change my Tabindex order?

Another related tactic is to use the tabindex attribute. A tabindex of -1 (tabindex="-1") will remove an element from the tab order. A tabindex of 0 (tabindex="0") will add an element to the focus order. It is highly recommended to avoid positive tabindex values and to structure your DOM in the correct order.

What is the difference between Tabindex 0 and Tabindex =- 1?

tabindex="1" (or any number greater than 1) defines an explicit tab or keyboard navigation order. This must always be avoided. tabindex="0" allows elements besides links and form elements to receive keyboard focus.

What is Tabindex and tab order how can we change a tab order of a control?

Tab order can be set in the Properties window of the designer using the TabIndex property. The TabIndex property of a control determines where it's positioned in the tab order. By default, the first control added to the designer has a TabIndex value of 0, the second has a TabIndex of 1, and so on.


2 Answers

This example will help you set the tabindex based on the columns:

function fixVerticalTabindex(selector) {
  if (typeof selector == 'undefined') {
    selector = '.reset-tabindex';
  }
  var tabindex = 1;
  $(selector).each(function(i, tbl) {
    $(tbl).find('tr').first().find('td').each(function(clmn, el) {
      $(tbl).find('tr td:nth-child(' + (clmn + 1) + ') input').each(function(j, input) {
        $(input).attr('placeholder', tabindex);
        $(input).attr('tabindex', tabindex++);
      });
    });
  });
}
$(function() {
  $('#btn-fix').click(function() {
    fixVerticalTabindex('.reset-tabindex');
  });
});
table {
  border: 1px solid red;
}

input {
  border: 1px solid black;
  width: 75px;
  height: 65px;
  font-size: 25px;
  text-align: center;
}
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>

<table class="reset-tabindex">
  <tr>
    <td><input /></td>
    <td>no input</td>
    <td>no input</td>
  </tr>
  <tr>
    <td>no input</td>
    <td><input /></td>
    <td><input /></td>
  </tr>
  <tr>
    <td><input /></td>
    <td>no input</td>
    <td><input /></td>
  </tr>
</table>
<br /><br />
<table class="reset-tabindex">
  <tr>
    <td><input /></td>
    <td><input /></td>
    <td><input /></td>
    <td><input /></td>
    <td><input /></td>
  </tr>
  <tr>
    <td>no input</td>
    <td>no input</td>
    <td>no input</td>
    <td>no input</td>
    <td><input /></td>
  </tr>
  <tr>
    <td><input /></td>
    <td><input /></td>
    <td><input /></td>
    <td><input /></td>
    <td><input /></td>
  </tr>
  <tr>
    <td>no input</td>
    <td>no input</td>
    <td><input /></td>
    <td><input /></td>
    <td><input /></td>
  </tr>
  <tr>
    <td>no input</td>
    <td>no input</td>
    <td><input /></td>
    <td><input /></td>
    <td><input /></td>
  </tr>
</table>
<br /><br />
<button id="btn-fix">Click to fix vertical tabindex</button>

The function will "fix" every table on it's own (will not mix between columns of different tables).

I didn't check the function for tables with colspan/rowspan, but my guess is that it will not work correctly.

The line $(input).attr('placeholder', tabindex); is there only for preview and debugging, you can remove on production.

like image 167
Dekel Avatar answered Sep 20 '22 20:09

Dekel


Based on this solution for arrow keys I modified the code to work also with enter key and the tab key with specified column-wise mode.

I don't think that it is the best idea to specify tabindex attributes for such case. You would have to recaltulate them on every change in number of columns or rows. Also it would change the flow of focusable elements on page (table first then its surrounding).

/*!
* based on formNavigation https://github.com/omichelsen/FormNavigation
*/
(function ($) {
  $.fn.formNavigation = function () {
    $(this).each(function () {
      // Events triggered on keyup
      $(this).find('input').on('keyup', function(e) {
        switch (e.which) {
          // arrow right
          case 39:
            $(this).closest('td').next().find('input').focus();
            break;

          // arrow left
          case 37:
            $(this).closest('td').prev().find('input').focus();
            break;

          // arrow bottom
          case 40:
            $(this).closest('tr').next().children().eq($(this).closest('td').index()).find('input').focus();
            break;

          // arrow top
          case 38:
            $(this).closest('tr').prev().children().eq($(this).closest('td').index()).find('input').focus();
            break;

          // enter
          case 13:
            if ($(this).closest('td').next().find('input').length>0) {
              // when there is another column on right
              $(this).closest('td').next().find('input').focus();
            } else {
              // when last column reached
              $(this).closest('tr').next().children().eq(1).find('input').focus();
            }
            break;
        }
      });
      
      // Events triggered on keydown (repeatable when holding the key)
      $(this).find('input').on('keydown', function(e) {
        // Vertical navigation using tab as OP wanted
        if (e.which === 9 && !e.shiftKey) {
          // navigate forward
          if ($(this).closest('tr').next().find('input').length>0) {
            // when there is another row below
            e.preventDefault();
            $(this).closest('tr').next().children().eq($(this).closest('td').index()).find('input').focus();
          } else if ($(this).closest('tbody').find('tr:first').children().eq($(this).closest('td').index()+1).find('input').length>0) {
            // when last row reached
            e.preventDefault();
            $(this).closest('tbody').find('tr:first').children().eq($(this).closest('td').index()+1).find('input').focus();
          }
        } else if (e.which === 9 && e.shiftKey) {
          // navigate backward
          if ($(this).closest('tr').prev().find('input').length>0) {
            // when there is another row above
            e.preventDefault();
            $(this).closest('tr').prev().children().eq($(this).closest('td').index()).find('input').focus();
          } else if ($(this).closest('tbody').find('tr:last').children().eq($(this).closest('td').index()-1).find('input').length>0) {
            // when first row reached
            e.preventDefault();
            $(this).closest('tbody').find('tr:last').children().eq($(this).closest('td').index()-1).find('input').focus();
          }
        }
      });
    });
  };
})(jQuery);

// usage
$('.gridexample').formNavigation();
/* For demonstration only */
.gridexample {
  font-size: 1.1em;
}
.gridexample th {
  padding: .15em .5em;
}
.gridexample td {
  padding: .1em;
  width: 5em;
}
.gridexample input[type="text"] {
  width: 100%;
  line-height: 2;
  box-sizing: border-box;
}
<p>
  Sample <a href="#">links</a> around the table (to simulate <a href="#">focus</a> outside the table).
</p>

<table class="gridexample">
  <thead>
    <tr>
      <th></th>
      <th>A</th>
      <th>B</th>
      <th>C</th>
      <th>D</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>1</th>
      <td><input type="text"></td>
      <td><input type="text"></td>
      <td><input type="text"></td>
      <td><input type="text"></td>
    </tr>
    <tr>
      <th>2</th>
      <td><input type="text"></td>
      <td><input type="text"></td>
      <td><input type="text"></td>
      <td><input type="text"></td>
    </tr>
    <tr>
      <th>3</th>
      <td><input type="text"></td>
      <td><input type="text"></td>
      <td><input type="text"></td>
      <td><input type="text"></td>
    </tr>
    <tr>
      <th>4</th>
      <td><input type="text"></td>
      <td><input type="text"></td>
      <td><input type="text"></td>
      <td><input type="text"></td>
    </tr>
  </tbody>
</table>

<p>
  Sample <a href="#">links</a> around the table (to simulate <a href="#">focus</a> outside the table).
</p>

<!-- jQuery needed for this solution -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
like image 38
actimel Avatar answered Sep 16 '22 20:09

actimel