使用javascript、jquery和PHP自动完成从数据库中提取城市的输入


Autocomplete input to pull cities from database with javascript, jquery and PHP

我有以下代码在输入中执行自动完成功能。就像当我输入字母"M"时,所有以"M"开头的城市都会显示在我的输入框中。如果我只有几个城市,但一旦我有数百或数千个城市,这个代码就可以工作,我猜是因为变量$list无法存储所有信息。

有更好的方法来解决这个问题吗?

谢谢

<?php
 include("config.php");
   $db = pg_connect("$db_host $db_name $db_username $db_password");
    $query = "SELECT * FROM cities";
    $result = pg_query($query);
    if (!$result) {
        echo "Problem with query " . $query . "<br/>";
        echo pg_last_error();
        exit();
    }
    $get_total_rows = pg_numrows($result);
    $i =  $get_total_rows; 
while($myrow = pg_fetch_assoc($result)) {
    $city = $myrow[city];
    $country = $myrow[country];
    if ($i == $get_total_rows){
        $list = "'" . $city . " (" . $country . ")'";
        $i = $i -1;
    }
    else {$list = $list . ", '" . $city . " (" . $country . ")'";} 
     }
?>
<form name="form1" method="post" action="searchresults.php" >
    <input id="hero-demo" autofocus type="search" name="search" placeholder="City" >
    <input type="submit" name="submit" value="Search">
</form>
<script src="jquery.auto-complete.js"></script>
<script>
    $(function(){
        $('#hero-demo').autoComplete({
            minChars: 1,
            source: function(term, suggest){
                term = term.toLowerCase();
                var choices = [<?= $list ?>];
                var suggestions = [];
                for (i=0;i<choices.length;i++)
                    if (~choices[i].toLowerCase().indexOf(term)) suggestions.push(choices[i]);
                suggest(suggestions);
            }
        });
    });
</script>

更新

这是jquery.auto-complete.js 的代码

(function($){
$.fn.autoComplete = function(options){
    var o = $.extend({}, $.fn.autoComplete.defaults, options);
    // public methods
    if (typeof options == 'string') {
        this.each(function(){
            var that = $(this);
            if (options == 'destroy') {
                $(window).off('resize.autocomplete', that.updateSC);
                that.off('blur.autocomplete focus.autocomplete keydown.autocomplete keyup.autocomplete');
                if (that.data('autocomplete'))
                    that.attr('autocomplete', that.data('autocomplete'));
                else
                    that.removeAttr('autocomplete');
                $(that.data('sc')).remove();
                that.removeData('sc').removeData('autocomplete');
            }
        });
        return this;
    }
    return this.each(function(){
        var that = $(this);
        // sc = 'suggestions container'
        that.sc = $('<div class="autocomplete-suggestions '+o.menuClass+'"></div>');
        that.data('sc', that.sc).data('autocomplete', that.attr('autocomplete'));
        that.attr('autocomplete', 'off');
        that.cache = {};
        that.last_val = '';
        that.updateSC = function(resize, next){
            that.sc.css({
                top: that.offset().top + that.outerHeight(),
                left: that.offset().left,
                width: that.outerWidth()
            });
            if (!resize) {
                that.sc.show();
                if (!that.sc.maxHeight) that.sc.maxHeight = parseInt(that.sc.css('max-height'));
                if (!that.sc.suggestionHeight) that.sc.suggestionHeight = $('.autocomplete-suggestion', that.sc).first().outerHeight();
                if (that.sc.suggestionHeight)
                    if (!next) that.sc.scrollTop(0);
                    else {
                        var scrTop = that.sc.scrollTop(), selTop = next.offset().top - that.sc.offset().top;
                        if (selTop + that.sc.suggestionHeight - that.sc.maxHeight > 0)
                            that.sc.scrollTop(selTop + that.sc.suggestionHeight + scrTop - that.sc.maxHeight);
                        else if (selTop < 0)
                            that.sc.scrollTop(selTop + scrTop);
                    }
            }
        }
        $(window).on('resize.autocomplete', that.updateSC);
        that.sc.appendTo('body');
        that.sc.on('mouseleave', '.autocomplete-suggestion', function (){
            $('.autocomplete-suggestion.selected').removeClass('selected');
        });
        that.sc.on('mouseenter', '.autocomplete-suggestion', function (){
            $('.autocomplete-suggestion.selected').removeClass('selected');
            $(this).addClass('selected');
        });
        that.sc.on('mousedown click', '.autocomplete-suggestion', function (e){
            var item = $(this), v = item.data('val');
            if (v || item.hasClass('autocomplete-suggestion')) { // else outside click
                that.val(v);
                o.onSelect(e, v, item);
                that.sc.hide();
            }
            return false;
        });
        that.on('blur.autocomplete', function(){
            try { over_sb = $('.autocomplete-suggestions:hover').length; } catch(e){ over_sb = 0; } // IE7 fix :hover
            if (!over_sb) {
                that.last_val = that.val();
                that.sc.hide();
                setTimeout(function(){ that.sc.hide(); }, 350); // hide suggestions on fast input
            } else if (!that.is(':focus')) setTimeout(function(){ that.focus(); }, 20);
        });
        if (!o.minChars) that.on('focus.autocomplete', function(){ that.last_val = ''n'; that.trigger('keyup.autocomplete'); });
        function suggest(data){
            var val = that.val();
            that.cache[val] = data;
            if (data.length && val.length >= o.minChars) {
                var s = '';
                for (var i=0;i<data.length;i++) s += o.renderItem(data[i], val);
                that.sc.html(s);
                that.updateSC(0);
            }
            else
                that.sc.hide();
        }
        that.on('keydown.autocomplete', function(e){
            // down (40), up (38)
            if ((e.which == 40 || e.which == 38) && that.sc.html()) {
                var next, sel = $('.autocomplete-suggestion.selected', that.sc);
                if (!sel.length) {
                    next = (e.which == 40) ? $('.autocomplete-suggestion', that.sc).first() : $('.autocomplete-suggestion', that.sc).last();
                    that.val(next.addClass('selected').data('val'));
                } else {
                    next = (e.which == 40) ? sel.next('.autocomplete-suggestion') : sel.prev('.autocomplete-suggestion');
                    if (next.length) { sel.removeClass('selected'); that.val(next.addClass('selected').data('val')); }
                    else { sel.removeClass('selected'); that.val(that.last_val); next = 0; }
                }
                that.updateSC(0, next);
                return false;
            }
            // esc
            else if (e.which == 27) that.val(that.last_val).sc.hide();
            // enter or tab
            else if (e.which == 13 || e.which == 9) {
                var sel = $('.autocomplete-suggestion.selected', that.sc);
                if (sel.length && that.sc.is(':visible')) { o.onSelect(e, sel.data('val'), sel); setTimeout(function(){ that.sc.hide(); }, 20); }
            }
        });
        that.on('keyup.autocomplete', function(e){
            if (!~$.inArray(e.which, [13, 27, 35, 36, 37, 38, 39, 40])) {
                var val = that.val();
                if (val.length >= o.minChars) {
                    if (val != that.last_val) {
                        that.last_val = val;
                        clearTimeout(that.timer);
                        if (o.cache) {
                            if (val in that.cache) { suggest(that.cache[val]); return; }
                            // no requests if previous suggestions were empty
                            for (var i=1; i<val.length-o.minChars; i++) {
                                var part = val.slice(0, val.length-i);
                                if (part in that.cache && !that.cache[part].length) { suggest([]); return; }
                            }
                        }
                        that.timer = setTimeout(function(){ o.source(val, suggest) }, o.delay);
                    }
                } else {
                    that.last_val = val;
                    that.sc.hide();
                }
            }
        });
    });
}
$.fn.autoComplete.defaults = {
    source: 0,
    minChars: 3,
    delay: 150,
    cache: 1,
    menuClass: '',
    renderItem: function (item, search){
        // escape special characters
        search = search.replace(/[-'/''^$*+?.()|[']{}]/g, '''$&');
        var re = new RegExp("(" + search.split(' ').join('|') + ")", "gi");
        return '<div class="autocomplete-suggestion" data-val="' + item + '">' + item.replace(re, "<b>$1</b>") + '</div>';
    },
    onSelect: function(e, term, item){}
};
}(jQuery));

所以这个答案有几个部分。

其中一部分是你的文件真的应该分开。第二,您应该使用ajax获取数据,而不是通过php插入数据。

由于我们不知道您是表结构,所以我将对查询进行一些自由处理。

这应该会让你走上正确的道路。它将PHP脚本设置为返回JSON对象,然后将其传递给自动完成函数。

PHP-数据.PHP

<?php
    // Loads Database Details
    include("config.php");
    // Creates Connection
    $db = pg_connect("$db_host $db_name $db_username $db_password");
    // Grabs Selection
    $userInput = $_GET['typed'];
    // Runs Query On Database
    $query = "SELECT * FROM cities";
    // Runs Query And Places It
    $result = pg_query($query);
    // Kills Script If No Results
    if (!$result) {
        echo "Problem with query " . $query . "<br/>";
        echo pg_last_error();
        return json_encode(array());
        die();
    }
    $list = pg_fetch($result);
    return json_encode($list);
?>

HTML/脚本

<form name="form1" method="post" action="searchresults.php" >
    <input id="hero-demo" autofocus type="search" name="search" placeholder="City" >
    <input type="submit" name="submit" value="Search">
</form>
<script src="jquery.auto-complete.js"></script>
<script>
    var DBsource = [];
    $('document').ready(function(){
        $.get("data.php", function(response){
            DBsource = response;
        });
        $('#hero-demo').autoComplete({
                minChars: 2,
                source: DBsource
            });
        });
    });
</script>

如果您愿意使用库,请考虑Select2。它可以从<select>元素或api中搜索大量选项,并具有多种选项

如果您有这么多城市,请将minChars增加到至少2个甚至更多。没有人愿意看到那个大的汽车配套箱。

通常您不会将所有数据带到客户端,但您会对插入的每个字符执行ajax调用(使用适当的debounce方法)。

无论如何,我会尝试将客户端代码与服务器代码分离,并尝试使用$.ajax函数

将数组作为json