How do I keep a selected LI visible (not hidden)?
Asked Answered
V

3

10

I'm using jQuery 1.12. I have a styled UL with LI elements. I use the below code to select these elements using the up or down arrows on the keyboard when the DIV has focus ...

 $(".select").bind('keydown', function(event) {
    var currentElement = $(this).find(".select-options li.selected");
    if (currentElement.length == 0) {
        currentElement = $(this).find(".select-options li")[0];
      $(currentElement).addClass("selected");
      return;
    }       // if
    var nextElement;
    switch(event.keyCode){
    // case up
    case 38:
        nextElement = $(this).find(".select-options li")[($(this).find(".select-options li").index(currentElement) - 1) % $(this).find(".select-options li").length];
        break;
    case 40:
        nextElement = $(this).find(".select-options li")[($(this).find(".select-options li").index(currentElement) + 1) % $(this).find(".select-options li").length];
      break;
    }
    $(this).find(".select-options li").removeClass("selected");
    if(nextElement !== null) {
        $(nextElement).addClass("selected");
    }
 });

The problem is, if you continually click the down key (for example), eventually you won't be able to see the selected item. How do I adjust things so that the selected item is always visible? The Fiddle illustrating the problem is here -- http://jsfiddle.net/sge8g5qu/1/ .

Vulgarity answered 3/1, 2017 at 14:46 Comment(3)
The best thing to do is, limit it inside the screen height. That's what Facebook or Google does.Plasm
Cna you edit my Fiddle to illustrate what you're talkign about?Vulgarity
As mentioned in How do I mimic keyboard behavior in my styled select dropdown?, the simplest solution is to use jQuery UI selectMenu widget, which is available and fully tested. You can also look at their code to see how they did it.Steep
G
11

At the end where you add the class to the nextElement call .scrollIntoView( false ) on it as well.

if(nextElement !== null) {
    $(nextElement).addClass("selected");
    nextElement.scrollIntoView(false); // added this line
}

Updated fiddle: http://jsfiddle.net/gaby/6fjnnu55/

Gerrilee answered 5/1, 2017 at 19:56 Comment(1)
@Pineda the restriction to FF applies only to using the scrollIntoViewOptions parameter.Gerrilee
C
1

You can use, .offset() to find the top offset of your select box and of the the selected element.

You can then use .scrollTop to set it, try something like:

var yourSelectInput = $('.select');

var nextElementTop = $(nextElement).offset().top;  // get offset of element
var selectTop = yourSelectInput.offset().top;  // get offset of select input

// set the scrollTop to the scroll input offset
// plus the difference of the option top offset
yourSelectInput.scrollTop(yourSelectInput.scrollTop() + (nextElementTop - selectTop));
Cumbrous answered 3/1, 2017 at 14:56 Comment(2)
So every time I select an element that can't be seen it will automatically scroll that item to the top? That might work for clikcing the up arrow key, but I think that looks clunky when clicking the down arrow key. I'd like it to behave like a select menu, which doesn't scroll all the way to the top.Vulgarity
You should be able to make it so that when you click down, the selected element will be scrolled so it appears at the bottom of the select input list pop-upCumbrous
L
1

Easiest way to achieve this is to allow focus on the li element by using tabIndex="0".

When you focus a new element the browser automatically scrolls to the selected element.

See snippet below.

$('.select-options li').on('keydown', function (e) {
  var key = e.which || e.keyCode;
  var nextElement = false;
  
  switch (key) {
    case 38: //Up
      nextElement = $(this).prev().length ? $(this).prev() : $(this).parent().find('li').last();
      break;
    case 40:
      nextElement = $(this).next().length ? $(this).next() : $(this).parent().find('li').first();
      break;
  };
   
  if (nextElement) {
    e.preventDefault();
     
    $('.selected').removeClass('selected');
    nextElement.addClass('selected').focus();
    
    console.log(nextElement);
  }
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul class="select-options">
  <li tabindex="0">Option 1</li>
  <li tabindex="0">Option 2</li>
  <li tabindex="0">Option 3</li>
  <li tabindex="0">Option 4</li>
  <li tabindex="0">Option 5</li>
  <li tabindex="0">Option 6</li>
  <li tabindex="0">Option 7</li>
  <li tabindex="0">Option 8</li>
  <li tabindex="0">Option 9</li>
  <li tabindex="0">Option 10</li>
  <li tabindex="0">Option 11</li>
  <li tabindex="0">Option 12</li>
  <li tabindex="0">Option 13</li>
  <li tabindex="0">Option 14</li>
  <li tabindex="0">Option 15</li>
  <li tabindex="0">Option 16</li>
  <li tabindex="0">Option 17</li>
  <li tabindex="0">Option 18</li>
  <li tabindex="0">Option 19</li>
  <li tabindex="0">Option 20</li>
</ul>
Lucilelucilia answered 3/1, 2017 at 15:13 Comment(2)
Nothing happens hwen I click "Run Code Snippet", I just see a list of dotted items that read "Option1," "Option2," etc.Vulgarity
Mark one of the elements (focus) with your mouse and use arrow down/arrow up to navigate through them.Lucilelucilia

© 2022 - 2024 — McMap. All rights reserved.