Search code examples
javascriptjqueryhtmlarrow-keys

jQuery: How to navigate from one td to a specific other td in a table


I am new to jQuery so I might approach this the wrong way but hope someone here can help me.

I have a pretty large HTML table that is created dynamically. To help the user I would like to bind a navigation event to the arrow keys only for this table. In this example I would like to "jump" from on div to the next div (they also have the class "myClass"). The table is larger than the example below but the structure always repeats so every third td has an (editable) div.

So far I couldn't get this to work but the function does catch the arrow press as I can show alerts this way.

My jQuery:

$(document).on('keydown', '#tblCalendar', function(e){
    switch(e.which) {
        case 37: // left
            // similar action to the left
            break;                  
        case 39: // right
            $(this).closest('td').next().next().next().find('div').focus();
            break;          
        default: return; // exit handler
    }
    e.preventDefault(); // prevent default action
});

My HTML (simplified):

<tbody>
    <tr>
        <td></td>
        <td></td>
        <td><div class="myClass"></div></td>
        <td></td>
        <td></td>
        <td><div class="myClass"></div></td>
        // ...
    </tr>
    // ...
</tbody>

Many thanks in advance, Mike


Solution

  • I've rebuild your function a little bit. Now it would involves only one DOM request to collect all editable elements and stores them in a variable. You can rotate through all of them using the left and right arrow keys. If no element is selected, it gets the first one. I've added a class to demonstrate that behavior. To adjust this to your needs, simply replace .addClass('active') with .get(0).focus().

    Example of the principal with a class that toggles

    var focusable = $('div.myClass');
    var current = null;
    
    $(document).on('keydown', function(event) {
        var next = null;
    
        if (37 == event.which || 39 == event.which) {
            if (null == current) {
                current = 0;
                focusable.eq(current).addClass('active');
                return;
            }
    
            if (37 == event.which) {
                next = current - 1;
                if (0 > next) {
                    next = focusable.length - 1;
                }
            }
    
            if (39 == event.which) {
                next = current + 1;
                if (focusable.length == next) {
                    next = 0;
                }
            }
    
            focusable.eq(current).removeClass('active');
            focusable.eq(next).addClass('active');
            current = next;
        }
    });
    

    Reduced code when there's no class toggle involved

    var focusable = $('div.myClass');
    var current = null;
    
    $(document).on('keydown', function(event) {
        if (37 == event.which || 39 == event.which) {
            if (null == current) {
                current = 0;
                focusable.eq(current).get(0).focus();
                return;
            }
    
            if (37 == event.which) {
                --current;
                if (0 > current) {
                    current = focusable.length - 1;
                }
            }
    
            if (39 == event.which) {
                ++current;
                if (focusable.length == current) {
                    current = 0;
                }
            }
    
            focusable.eq(current).get(0).focus();
        }
    });
    

    Demo

    Try before buy
    Try before buy with focusable divs