0

I have a fixed height div with overflow-y set to scroll

Within this div there is a table wherein the rows (i.e., <tr>s) are "selectable" (i.e., they highlight with some jQuery working with css [this is already set up and included in the code I've pasted below]).

To this, I've also added the ability to move up and down via the up and down arrows on the keyboard (this is also already functional and included in the code below).

The problem I'm having, of course, is that when a user is scrolling up and down (via the up and down arrow keys on the keyboard) the window (i.e., the scrollable <div>) doesn't scroll with the selected row when the row is out of visible range.

How can I get the <div>s scrollbar to scroll with the currently selected <tr> as the user arrows down or up the table rows and those rows exist out of view?

Here is the relevant jquery for all of the functionality so far:

////**********GLOBAL VARIABLES*********//////
var clientRowHighlighted = false;
////**********global variables*********//////

function bindArrows() {
    $(document).keydown(function (e) {
        if (clientRowHighlighted) {
            switch (e.which) {
                case 38: //up
                    $("#selected").prev().click();
                    if (!isScrolledIntoView($("#selected"))) {
                        scrollToView($("#selected"));
                    }
                    break;

                case 40: //down
                    $("#selected").next().click();
                    if (!isScrolledIntoView($("#selected"))) {
                        scrollToView($("#selected"));
                    }
                    break;

                default: return; //exit this handler for other key presses
            }
            e.preventDefault(); //prevent the default action (scroll / move caret)
        }
    });
}

function bindClientSearchRows() {
        $(".selectable").click(function () {
            $(".selectable").attr('id', '');
            $(this).attr('id', 'selected');
            $(".selectable").css("background-color", "initial");
            $(this).css("background-color", "#57b7ff");
            var cn = $(this).children().first().text();
            $("#trackedClientNumber").val(cn);
            clientRowHighlighted = true;
            fillCSTStep1(cn); //This function is irrelevant to this StackOverflow question.
        });
}

A short example of the table itself in html (using some C# for inner values):

<div id="clientSearchList" class="clientInfoWrapper">
    <table id="clientsFound" class="clientSearchTable">
        @foreach (var row in db.Query(queryAll))
        {
            <tr class="selectable">
                <td class="clientNumber">@row.ClientNumber</td>
                <td class="clientName">@row.CompanyName</td>
                <td class="clientAddress">@row.CompanyAddress</td>
                <td class="clientCity">@row.CompanyCity</td>
                <td class="clientState">@row.CompanyState</td>
                <td class="clientZip">@row.CompanyZip</td>
                <td class="clientMarket">@row.Market</td>
                <td class="clientActive">
                    @if (row.ClientActive == true)
                    {
                        clientActive = "Yes";
                    }
                    else if (row.ClientActive == false)
                    {
                        clientActive = "No";
                    }
                    else
                    {
                        clientActive = row.ClientActive;
                    }
                    @clientActive
                </td>
            </tr>
        }
    </table>
</div>

And, finally, some relevant CSS:

tr.selectable
{
    cursor: pointer;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

.clientInfoWrapper
{
    height: 200px;
    overflow-y: scroll;
    overflow-x: hidden;
    border: 2px inset #888;
    background-color: #dcf8f4; /*Default Solid Background Color (Lighter Color)*/
    /* Opera 11.10+ */
    background: -o-linear-gradient(bottom, #aaeee5, #dcf8f4); /*Bottom-Top*/
    /* Firefox 3.6+ */
    background: -moz-linear-gradient(bottom, #aaeee5, #dcf8f4); /*Bottom-Top*/
    /* Chrome 7+ & Safari 5.03+ */
    background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #aaeee5), color-stop(1, #dcf8f4)); /*Bottom-Top*/
    /* Newer Browsers */
    background: linear-gradient(bottom, #aaeee5, #dcf8f4); /*Bottom-Top*/
    /* IE8 */
    -ms-filter: "progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#dcf8f4,EndColorStr=#aaeee5)"; /*Top-Bottom*/
    /* IE5.5 - IE7 */
    filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#dcf8f4,EndColorStr=#aaeee5); /*Top-Bottom*/
}

.clientSearchTable
{
    white-space: nowrap;
    table-layout: fixed;
    font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
}

I'd add more CSS but I think I've added all that is relevant, and I don't want to unnecessarily bloat this page, but if more is needed please ask.

I've searched Stack Overflow for some relevant answers that may already exist, and while the answers I found were very informative about the nature of the beast I'm trying to tame here, I couldn't quite get them to work for my needs.

Here are a couple of the links I've already checked out:

How to Check if element is visible after scrolling?

Scroll if element is not visible

Adding functionality for using the up and down arrow keys to select a table row

But none of these answers quite apply to what I'm trying to do, it seems.

halfer
  • 19,824
  • 17
  • 99
  • 186
VoidKing
  • 6,282
  • 9
  • 49
  • 81

1 Answers1

2

This code is what I'm using in my current project to scroll a container that I can highlight with the arrow keys:

  function scrollElementUp() {
    var childElement = /*get the tr you want to scroll somehow*/
    var parentElement = /*get the container with the scrollbar*/
    var parentClientRect = parentElement.getBoundingClientRect();
    var parentBottom = parentClientRect.bottom;
    var parentTop = parentClientRect.top;

    var childRect = childElement.getBoundingClientRect();
    var childBottom = childRect.bottom;
    var childTop = childRect.top;
    if(childBottom > parentBottom) {
      parentElement.scrollTop += childRect.height;
    }
    if(childTop < parentTop) {
      parentElement.scrollTop -= childRect.height;
    }
  }

I'm just checking to see if the bottom of the element you want to scroll is below the bottom of the scroll container (and the opposite for scrolling back up with the tops). If it is, I move the scrollTop an amount equal to the height of the element I want to scroll to.

SethWhite
  • 1,891
  • 18
  • 24