Reputation: 7497
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
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