CherryFlavourPez
CherryFlavourPez

Reputation: 7497

Navigate through multiple lists using arrow keys/jQuery?

This question has a useful answer showing how to use jQuery to navigate up and down a list, which you can see here. The code is this:

var li = $('li');
var liSelected;
$(window).keydown(function(e){
    if(e.which === 40){
        if(liSelected){
            liSelected.removeClass('selected');
            next = liSelected.next();
            if(next.length > 0){
                liSelected = next.addClass('selected');
            }else{
                liSelected = li.eq(0).addClass('selected');
            }
        }else{
            liSelected = li.eq(0).addClass('selected');
        }
    }else if(e.which === 38){
        if(liSelected){
            liSelected.removeClass('selected');
            next = liSelected.prev();
            if(next.length > 0){
                liSelected = next.addClass('selected');
            }else{
                liSelected = li.last().addClass('selected');
            }
        }else{
            liSelected = li.last().addClass('selected');
        }
    }
});

I want to achieve something similar, but slightly more complex. Rather than a single list, I will have multiple lists on my page. I have set them up so that they can be tabbed to. Once that list has focus, I want the up/down arrow keys to move through the list.

I also would like to understand why the code above adds/removes class rather than actually giving the element focus using element.focus();

My HTML markup:

<ul tabindex="0" id="client-list" class="tabbable">
    <li tabindex="-1">Client 1</li>
    <li tabindex="-1">Client 2</li>
</ul>

<ul tabindex="0" id="product-list" class="tabbable">
    <li tabindex="-1">Product 1</li>
    <li tabindex="-1">Product 2</li>
</ul>

I have tried amending the keydown function to test which element is currently active:

if ( tabList.hasFocus ) {...

But to no avail. I guess this is a non-starter because that element won't have focus, but the child li items will.

Upvotes: 0

Views: 5041

Answers (1)

Ben
Ben

Reputation: 867

I have modified the existing code in your fiddle to work:

http://jsfiddle.net/path411/8Pku9/

var $liSelected;
var $ulSelected;
$(window).keydown(function(e) {
    // Make sure we have a ul selected
    if($ulSelected) { 

        if(e.which === 40) {            
            if($liSelected) {
                $liSelected.removeClass('selected');
                var $next = $liSelected.next();
                if($next.length) {
                    $liSelected = $next.addClass('selected');
                }
                else {
                    $liSelected = $ulSelected.children('li').first().addClass('selected');  
                }
            }
            else {
                $liSelected = $ulSelected.children('li').first().addClass('selected');            
            }
        }else if(e.which === 38) {            
           if($liSelected) {
                $liSelected.removeClass('selected');
                var $prev = $liSelected.prev();
                if($prev.length) {
                    $liSelected = $prev.addClass('selected');
                }
                else {
                    $liSelected = $ulSelected.children('li').last().addClass('selected');  
                }
            }
            else {
                $liSelected = $ulSelected.children('li').last().addClass('selected');            
            }
        }

    }
});


$('ul').focus(function(e) {
    $ulSelected = $(this);
    $liSelected.removeClass('selected');
    $liSelected = false;
});
  • The first thing that needed to be done was to save which ul was focused by using $.focus().

  • .next() and .prev() already only work on siblings, so by using 2 different uls, that functionality works fine.

  • On first press of up/down as well as when you want to cycle through the last/first items, I had to change finding the first()/last() from the selected ul that was saved earlier, rather than a global list of lis.

  • In my edit I did change the saved jquery elements to use the more common semantic of starting their name with a $, this isn't a necessary change.

To answer your other question, by using classes instead of .focus, it is much easier to keep track of the selected element, as well as style it.

Upvotes: 2

Related Questions