Reputation: 323
I have a set of list items that contain nested lists, sort of like this:
<ul class="searchselectors">
<li class="group">Group name 1
<ul>
<li class="item selected">List item 1.1</li>
<li class="item">List item 1.2</li>
<li class="item">List item 1.3</li>
</ul>
</li>
<li class="group">Group name 2
<ul>
<li class="item">List item 2.1</li>
<li class="item">List item 2.2</li>
<li class="item">List item 2.3</li>
</ul>
</li>
<li class="group">Group name 3
<ul>
<li class="item">List item 3.1</li>
</ul>
</li>
</ul>
I want to cycle through all of the .item
elements using up/down arrow keys (which I already have set up by using on('keydown')
and catching key codes 38
and 40
) and set .selected
on the next item before or after the currently selected item, wrapping around to the top/bottom as necessary.
Using $().next()
and $().prev()
will not work, since it will only work on siblings, and not on a jQuery object such as $('.searchselectors .item')
.\
Upvotes: 1
Views: 157
Reputation: 10976
In my quest to provide native JS answers to those looking for it, here is @Mario j Vargas' good answer adapted in native Javascript. It only takes 2 lines of extra code.
http://jsfiddle.net/kevinvanlierde/7tQSW/2/
Only putting the JS up here, HTML is the same.
(function () {
var $menu = document.getElementById('searchselectors'),
items = $menu.getElementsByClassName('item'),
$selectedItem = $menu.getElementsByClassName('selected')[0],
selectedIndex = Array.prototype.indexOf.call($selectedItem, items)+1;
document.body.addEventListener('keydown', function (e) {
switch(e.keyCode) {
case 40: // down arrow
$selectedItem.className = $selectedItem.className.replace(' selected','');
selectedIndex = selectedIndex < items.length - 1 ? selectedIndex + 1 : selectedIndex;
$selectedItem = items[selectedIndex];
$selectedItem.className += ' selected';
break;
case 38: // up arrow
$selectedItem.className = $selectedItem.className.replace(' selected','');
selectedIndex = selectedIndex > 0 ? selectedIndex - 1 : selectedIndex;
$selectedItem = items[selectedIndex];
$selectedItem.className += ' selected';
break;
}
}, false);
}());
Upvotes: 1
Reputation: 1195
I was working on the same problem but in my project I'm using KnockoutJS. In fact, the original logic was written with pure jQuery and I refactored it with Knockout. Here's a solution for your problem using jQuery:
Fiddle - http://jsfiddle.net/6QN77/2/
I didn't spend too much time cleaning up the JavaScript, but I'm leaving that to you now.
HTML
<ul id="searchselectors">
<li class="group">Group name 1
<ul>
<li class="item selected">List item 1.1</li>
<li class="item">List item 1.2</li>
<li class="item">List item 1.3</li>
</ul>
</li>
<li class="group">Group name 2
<ul>
<li class="item">List item 2.1</li>
<li class="item">List item 2.2</li>
<li class="item">List item 2.3</li>
</ul>
</li>
<li class="group">Group name 3
<ul>
<li class="item">List item 3.1</li>
</ul>
</li>
</ul>
jQuery
$(function () {
var $menu = $("#searchselectors"),
$items = $menu.find(".item"),
$selectedItem = $menu.find(".selected"),
selectedIndex = $selectedItem.length - 1;
$(document).on("keydown", function (e) {
switch(e.keyCode) {
case 40: // down arrow
$selectedItem.removeClass("selected");
selectedIndex = (selectedIndex + 1) % $items.length;
$selectedItem = $items.eq(selectedIndex).addClass("selected");
break;
case 38: // up arrow
$selectedItem.removeClass("selected");
selectedIndex = (selectedIndex - 1) % $items.length;
$selectedItem = $items.eq(selectedIndex).addClass("selected");
break;
}
});
});
UPDATE: My solution revolves around getting a reference to a wrapper element (#searchselectors
) and getting all the LI
elements marked with the CSS class .item
. Next I get a reference to the currently selected element and its index. Finally, the code listens to the down and up arrow keys being pressed (keydown
), decrementing if going up and incrementing if going up. Cycling is achieved via the modulus operator. The selected item's CSS class is removed and put back. The selected item reference is used for performance reasons so I don't have to write $items.removeClass(".selected").eq(selectedIndex).addClass("selected");
Upvotes: 4
Reputation: 4824
Easiest way to get all the list items with class "item" is:
var items = $('.item');
for (var i = 0; i < items.length; i++) {
var item = items[i]; // iterate
}
And then, you can select the next item from the list
OR
you can do this
if (!$().next) {
var nextUL= $().parent.find('ul')
iterateThruList(nextUL);
}
Upvotes: 0
Reputation: 27
You could use something like
var UL = $(".searchselectors").children().length; //number of UL (group names)
to iterate through items.
Upvotes: -1