自动建议下拉菜单未使用向上/向下箭头键选择

I have a pretty basic auto-suggestion function for my website which operates whenever a user enters something into my search input.

It is supposed to function kind of like Googles search auto-suggestion - and it sort of does. However, when some suggestions are returned, if the user hits one of the arrows on their keyboard, it will not select any suggestion.

Here is my JS (for the selection of a suggestion):

$(document).ready(function(){
    var $result = $('li');

    $('input').keydown(function(e){
        var key = e.keyCode, $selected = $result.filter('.selected'), $current;
        if(key != 40 && key != 38){ 
            return;
        }
        $result.removeClass('selected');
        if (key == 40){
            if (!$selected.length || $selected.is(':last-child')){
                $current = $result.eq(0);
            } else {
                $current = $selected.next();
            }
        } else if (key == 38){
            if (!$selected.length || $selected.is(':first-child')){
                $current = $result.last();
            } else {
                $current = $selected.prev();
            }
        }

        $current.addClass('selected');
    });
});

Here is my Ajax:

function findmatch(){
    if(window.XMLHttpRequest){
        xmlhttp = new XMLHttpRequest();
    } else {
        xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
    }

    xmlhttp.onreadystatechange = function(){
        if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
            document.getElementById('s-dif').innerHTML = xmlhttp.responseText;
        }
    }

    var qVal = document.getElementById('query-value');

    xmlhttp.open('GET', 'search/suggest.php?q=' + qVal.value, true);
    xmlhttp.send();
}

The very basic HTML:

<div class="form-container">
    <form method="get" id="search" name="search">
        <input type="text" name="q" id="query-value" onkeyup="findmatch();" placeholder="Search with Ajax...">
    </form>
</div>
<div class="suggestions">
    <ul id="s-dif">
    </ul>
</div>

and finally, my PHP:

if(isset($_GET['q'])){
    $results = '';

    $query = trim($_GET['q']);  
    if(!empty($query)){
        $stmt = $conn->prepare("SELECT title, popularity FROM autosuggest WHERE keywords LIKE :query OR title LIKE :query ORDER BY popularity desc LIMIT 7");
        $query = $query . '%';
        $stmt->bindParam(':query', $query);
        $stmt->execute();

        $count = $stmt->rowCount();
        $i = 0;
        if($count > 0){
            while($row = $stmt->fetch(PDO::FETCH_OBJ)){
                $title = $row->title;
                $popularity = $row->popularity;

                $i++;

                $results .= '<li id="select-suggest" value="' . $i . '" name="' . $title . '">' . $title . '</li>';
            }   
        }
    }
}

print("$results");

I feel as if the problem lies within my "selection jQuery", however, I have made sure to triple check everything, but I cannot seem to find anything that would stop the feature from working.

I am not sure how Google works, but I believe you are try to do something like the below script. You should be able to apply it to your returned dropdown menu. It checks that the cursor is focused in the input field. If it is, then activate the keyCode script below:

jsFiddle: https://jsfiddle.net/2wvs0tmd/

JavaScript:

// I am going to use an object, just for reuse
/*
** @param jQuery [object] Pass the jQuery object
** @param getMenu [object] jQuery DOM object (ul) that contains our menu
** @parm getKeyTap [int] This is the e.keyCode passed from the event
*/
var keyAction   =   function(jQuery,getMenu,getKeyTap)
    {
        // The variable is what is currently be acted on
        var isSelected;
        // This will designate first or last child
        var getChild;
        // This will be assigned the next, previous, or current child
        var thisChild;
        // We assign jQuery here
        var $           =   jQuery;
        // These are all the keys we allow to be struck
        var allowKeys   =   [38,40,13];
        // This is not used in this example, but can reset the keyCode
        var keyCode     =   false;
        /*
        ** @returns [boolean] This function returns if the key being pressed is arrow up/down
        */
        var upDown      =   function(getKeyTap)
            {
                return (getKeyTap == 38 || getKeyTap == 40);
            }
        /*
        ** @returns [boolean] This method returns boolean true/false if up/down arrow pressed
        */
        this.keyAllowed =   function()
            {
                return upDown(getKeyTap);
            }
        /*
        ** @description This method sees if pressed key is up/down arrow or return key
        ** @returns [boolean] Will return true/false
        */
        this.isAllowed  =   function()
            {
                return (allowKeys.indexOf(getKeyTap) != -1);
            }
        // This will manually set the keyCode (not required in this example)
        this.setKey =   function(keyCode)
            {
                getKeyTap   =   keyCode;
                return this;
            }
        /*
        ** @returns [object] This returns the current state of the DOM 
        */
        this.isSelected =   function()
            {
                return isSelected;
            }
        /*
        ** @description This will run an anonymous function passing the current DOM
        ** @param thisChild [ANY] I pass the current DOM selection but, you 
        **                        can pass whatever you want 
        ** @param func [function] This is what you want to run when the 
        **                        return key is pressed
        */
        this.setReturn  =   function(thisChild,func)
            {
                if(getKeyTap == 13) {
                    if(thisChild)
                        func(thisChild);
                }
            }
        /*
        ** @description This will set the current DOM and add the select class
        ** @returns This will return the current DOM object
        */
        this.firstClick =   function()
            {
                getChild    =   (getKeyTap == 38)? 'last' : 'first';
                isSelected  =   getMenu.children('li:'+getChild+'-child');
                isSelected.addClass('selected');
                return isSelected;
            }
        /*
        ** @description This method will move the selection up and down
        ** @param isSelected [object] This is the current select DOM object
        ** @returns [object] this will return the current selected DOM object
        */
        this.currClick  =   function(isSelected)
            {
                var setSpot =   'last';

                if(getKeyTap == 38)
                    thisChild   =   isSelected.prev();
                else if(getKeyTap == 40) {
                    thisChild   =   isSelected.next();
                    setSpot     =   'first';
                }

                if(!thisChild.hasClass('selectable'))
                    thisChild   =   getMenu.children("li:"+setSpot+"-child");

                isSelected.removeClass('selected');
                thisChild.addClass('selected');
                return thisChild;
            }

        /*
        ** @description This will just run a function
        */
        this.doAction   =   function(func)
            {
                return func();
            }
    }

// When document is ready
$(document).ready(function(){
    // Set container for this menu
    var isSelected  =   false;
    var qBox        =   $('input[name=q]');
    // Use the document object to listen for a key press
    $(this).keydown(function(e) {
        // See where the cursor is focused
        var isFocused   =   (e.target.nodeName == 'INPUT');
        // Start engine
        var sMenu       =   new keyAction($, $('ul'), e.keyCode);
        // If it's focused
        if(isFocused) {
            // Place text into field on return          
            sMenu.setReturn(isSelected,function(obj) {
                qBox.val(isSelected.text());
                // Submit form
                $('#search').submit();
            });

            // If keys are allowed
            if(sMenu.keyAllowed()) {
                isSelected  =   (!isSelected)? sMenu.firstClick(isSelected) : sMenu.currClick(isSelected);
                // Copy the value of the selection into the input
                sMenu.doAction(function(){
                    qBox.val(isSelected.text());
                });
            }
        }
    });
    // On key up in the text field
    qBox.on('keyup',function(e){
        // If the key pressed is up or down arrow
        if(e.keyCode == 38 || e.keyCode == 40)
            // Don't do ajax call
            return false;
        // Run ajax
        $.ajax({
            url:"search/suggest.php",
            type:"get",
            data: $(this).serialize(),
            success:function(response) {
                $('#dropdown_search').html(response);
            }
        });
    });
});

Style:

.selected {
    background-color: #888;
}

HTML: Form

<div class="form-container">
    <form id="search" name="search">
        <input type="text" name="q" id="query-value" placeholder="Search with Ajax...">
    </form>
</div>
<ul id="dropdown_search">
</ul>

HTML: Returned from ajax (just example)

<li class="selectable">666554366</li>
<li class="selectable">1174971318</li>
<li class="selectable">1809433410</li>
<li class="selectable">452149182</li>
<li class="selectable">2024548770</li>