2016-08-01 60 views
4

我正在尝试使用我的ajax调用一起工作materializecss autocomplete plugin,以根据输入字段上输入的内容动态加载数据。如何使用ajax实现自动完成插件?

我的ajax请求在一个keydown事件中被调用。所有获取的数据都会自动推送到键/值对象数组中。

然后,我把自动完成功能放在ajax的成功函数中,而“数据”键的值就是之前建立的对象数组。

看来我很好,但是当我在浏览器中测试时,每次我输入内容时,建议下拉菜单都会按预期结果显示,但不会在每次按下后重新更新,另一个下拉列表重叠前一个,所以...

所以这是我的问题:如何避免下拉建议列表重叠,而不是每次按下按钮时更新?

谢谢你的帮助。

var dat = {}; 
 
\t $('input').on('keydown',function(e){ 
 
\t \t var d = { 
 

 
     "query": { 
 
         "prefix": { 
 
          "body": e.target.value 
 
         } 
 
        } 
 

 
     }; 
 
\t 
 
\t \t $.ajax({ 
 
     url:'https://xxxxxxxxxxxxxxx.eu-west-1.es.amazonaws.com/xxxxxxxxxxxxx', 
 
     type:'POST', 
 
     contentType : "application/json", 
 
     crossDomain : true, 
 
     data:JSON.stringify(d), 
 
     dataType:'JSON', 
 
     async:true, 
 
     success: function(da){ 
 
\t \t \t 
 
\t \t \t var c = da.hits.hits.length; 
 
\t \t \t for(var i = 0; i < c; i++){ 
 
\t \t \t \t dat[da.hits.hits[i]._source.body] = null; 
 
\t \t \t } 
 
\t \t \t 
 
\t \t $("input").autocomplete({ 
 
\t data : dat 
 
\t 
 
\t \t 
 
     }, 
 
     error: function(jqXHR, errorStatus, errorThrown){ 
 
      console.log(jqXHR); 
 
      console.log(errorStatus); 
 
      console.log(errorThrown); 
 
     } 
 

 
     }) 
 
\t \t

+0

你让我们都处于劣势。你可以看到你的代码,我们不能。 – BobRodes

+0

@BobRodes对不起,我认为在这种情况下解释更准确。现在你可以检查代码 –

回答

0

autocomplete()功能缺失的选项列表对象的右括号,收盘括号的功能本身,而需要遵循的分号。尝试修复这些,看看你得到:

success: function(da){   
     var c = da.hits.hits.length; 
     for(var i = 0; i < c; i++){ 
      dat[da.hits.hits[i]._source.body] = null; 
     } 
     $("input").autocomplete({ 
      data : dat 
     }); <----HERE 
    }, 

好的。你已经修复了括号,但仍然存在问题。首先,我会说,我不清楚为什么每次用户按下某个键时,都会尝试用新数据重新初始化自动填充小部件。当我打开页面时,我会初始化它,然后如果数据发生变化,我会重新初始化它。用户按下某个键后,可用选择不会改变。

但是,不要说:看着文档,这很粗略,你已经做了它告诉你要做的事情。它没有解决如何用新数据重新初始化现有的窗口小部件。在重新初始化之前,您可能必须找到一种方法来删除先前的列表。下面是他们说他们Select插件的东西:

如果要更新里面的选择项目,从上面只是重新运行初始化代码编辑原始选后。或者您可以使用下面的这个功能摧毁材料选择,并创建一个新的选择。

也许这也适用于autocomplete小工具,他们只是没有记录它。所以,我会先试试这个:

 $("input").autocomplete("destroy") 
     .autocomplete({ 
      data : dat 
     }); 

销毁现有的自动填充,然后用您的新数据重新初始化它。如果这不起作用(他们没有说他们支持自动完成的方法,但是直到你尝试才会知道),那么你需要深入DOM,找到保存数据的元素,并在调用autocomplete()函数之前编写代码将其删除。如果失败了,那么你可能会考虑使用jquery-ui自动完成功能,因为比你使用的更多的人使用它,你可以得到更好的帮助。

+0

谢谢。但始终是同一个问题。下拉列表是每次重复按下一个键,并有几个下拉列表重叠 –

+0

所以,你固定括号,仍然有问题? – BobRodes

+0

是的,我固定括号和分号。仍然是相同的问题 –

3

在这里,一个更简洁的例子。

  • 它基于的Materialized.js原有功能
  • 取消现有的Ajax请求您键入所以如果去掉“超时”注释行你没有得到双重结果
  • ,这样只会调用在按键后经过'x'时间之后的ajax调用。当您快速输入以避免在每次按键操作时发出Ajax呼叫(即使它们被取消)时,这可能会很有用。

见下文:

initAutoComplete({inputId:'autocomplete-input',ajaxUrl:'/search/my-auto-complete-results'}) 


function initAutoComplete(options) 
{ 
    var defaults = { 
    inputId:null, 
    ajaxUrl:false,  
    data: {} 
    }; 

    options = $.extend(defaults, options); 
    var $input = $("#"+options.inputId); 

    if (options.ajaxUrl !== false) 
    { 
    var $autocomplete = $('<ul id="myId" class="autocomplete-content dropdown-content"></ul>'), 
     $inputDiv = $input.closest('.input-field'), 
     //timeout, 
     runningRequest = false, 
     request; 

    if ($inputDiv.length) { 
     $inputDiv.append($autocomplete); // Set ul in body 
    } else {  
     $input.after($autocomplete); 
    } 

    var highlight = function(string, $el) { 
     var img = $el.find('img'); 
     var matchStart = $el.text().toLowerCase().indexOf("" + string.toLowerCase() + ""), 
      matchEnd = matchStart + string.length - 1, 
      beforeMatch = $el.text().slice(0, matchStart), 
      matchText = $el.text().slice(matchStart, matchEnd + 1), 
      afterMatch = $el.text().slice(matchEnd + 1); 
     $el.html("<span>" + beforeMatch + "<span class='highlight'>" + matchText + "</span>" + afterMatch + "</span>"); 
     if (img.length) { 
     $el.prepend(img); 
     } 
    }; 

    $autocomplete.on('click', 'li', function() { 
     $input.val($(this).text().trim()); 
     $autocomplete.empty(); 
    }); 

    $input.on('keyup', function (e) { 

     //if(timeout){ clearTimeout(timeout);} 
     if(runningRequest) request.abort();  

     if (e.which === 13) { 
     $autocomplete.find('li').first().click(); 
     return; 
     } 

     var val = $input.val().toLowerCase(); 
     $autocomplete.empty(); 

     //timeout = setTimeout(function() { 

     runningRequest=true; 

     request = $.ajax({ 
      type: 'GET', // your request type 
      url: options.ajaxUrl,   
      success: function (data) { 
      if (!$.isEmptyObject(data)) { 
       // Check if the input isn't empty 
       if (val !== '') { 
       for(var key in data) { 
        if (data.hasOwnProperty(key) && 
         key.toLowerCase().indexOf(val) !== -1 && 
         key.toLowerCase() !== val) { 
        var autocompleteOption = $('<li></li>'); 
        if(!!data[key]) { 
         autocompleteOption.append('<img src="'+ data[key] +'" class="right circle"><span>'+ key +'</span>'); 
        } else { 
         autocompleteOption.append('<span>'+ key +'</span>'); 
        } 
        $autocomplete.append(autocompleteOption); 

        highlight(val, autocompleteOption); 
        } 
       } 
       } 
      }      
      }, 
      complete:function(){ 
      runningRequest = false; 
      }   
     }); 
     //},250); 
    }); 
    } 
    else 
    { 
    $input.autocomplete({ 
     data: options.data 
    }); 
    } 
} 
+0

使用它并调整到我的用例后,像魅力一样工作,很好的方法寿 –

0

我工作围绕这一问题这样做。

<script src="jquery/2.1.4/jquery.js" type="application/javascript"></script> 
<script src="/js/default.js" type="application/javascript"></script> 
<script src="materializecss/0.97.7/js/materialize.js" type="application/javascript"></script> 

请注意库中间的文件“default.js”。

“default.js”

$.fn.alterAutocomplete = $.fn.autocomplete; 

然后和地方我需要使用自动完成插件我这样做。

$('#autocomplete-input').alterAutocomplete ({ 
    source: function (request, response) { 

    }, 
    response: function (event, ui) { 
     if (ui.content.length <= 0) { 
      ui.content.push({label: "No results"}); 
     } 
    }, 
    select: function (event, ui) { 
    } 
}); 
1

晚会有点晚,但认为这可能会帮助一些人在同一个问题上挣扎。

我找到的一种方法是制作autocomplete()返回的对象的副本,然后使用内置的data()函数对迭代结果进行复制并添加它们。需要一个新副本,否则它只是将额外的值添加到对象中(我确信有一些方法来清理对象,但所有常用方法都失败了)。

var data = [{ 
 
    key : 'One' 
 
}, { 
 
    key : 'Two' 
 
}, { 
 
    key : 'Three' 
 
}, { 
 
    key: 'Twenty One' 
 
}, { 
 
    key: 'Thirty Five' 
 
}, { 
 
    key: 'Three Thousand' 
 
}]; // Dummy data to emulate data from ajax request 
 

 
function autocompleteData(field) { 
 
    window.acSearch = $.ajax({ 
 
     url: 'somescript.php', 
 
     type: 'GET', 
 
     data: { 
 
     key: function() { 
 
      return $(field).val().trim(); 
 
     } 
 
     }, 
 
     success: function(data) { 
 
     $('.autocomplete-content').remove(); // Clear the old elements 
 
     var newData = $.extend({}, $(field).autocomplete()); // Create copy of autocomplete object 
 
     for (var i = 0; i < 20 && i < data.length; i++) { 
 
      newData.data((data[i]["key"]), null); // Iterate through results and add to the copied autocomplete object (I set the limit to 20 as this is the limit I set below for the autocomplete) 
 
     \t } 
 

 
     $(field).autocomplete({ 
 
     data: newData.data(), 
 
     limit: 20, // Limit the number of results 
 
     }); 
 
     $(field).keyup(); // This is just to get it to show the updated autocomplete results 
 
    }, 
 
    error: function(){ // Ajax request will error as the URL is invalid so we will use the dummy data var created earlier and process the same function on error as we would on success - THIS IS NOT NEEDED (it's just for demonstrative purposed) 
 
     $('.autocomplete-content').remove(); 
 
     var newData = $.extend({}, $(field).autocomplete()); 
 
     for (var i = 0; i < 20 && i < data.length; i++) { 
 
      newData.data(data[i]["key"], null); 
 
     \t } 
 

 
     $(field).autocomplete({ 
 
     data: newData.data(), 
 
     limit: 20, 
 
     }); 
 
     $(field).keyup(); 
 
    }, 
 
    complete: function(data) { 
 
     setTimeout(function() { 
 
     $(field).keyup() 
 
     }, 250); 
 

 
    } 
 
    }); 
 
} 
 

 
// Event handler on input field to trigger our function above and to clear any pending ajax requests 
 
$('#autocompleteInput').on('input', function(e) { 
 
    if (typeof acSearch != 'undefined') { 
 
    acSearch.abort(); 
 
    } 
 
    autocompleteData(this); 
 
});
<head> 
 
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/css/materialize.min.css" rel="stylesheet"/> 
 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/js/materialize.min.js"></script> 
 
<head> 
 
<body> 
 
<div class="container"> 
 
    <label for="autocompleteInput">Example Autocomplete</label> 
 
    <div class="input-field"> 
 
    <input id="autocompleteInput" class="autocomplete"> 
 
    </div> 
 
</div> 
 
</body>

3

大厦@ friek108的出色答卷的顶部,让我们增加了以下功能。

  • 单击外部时关闭自动填充小部件。
  • 允许使用箭头键滚动结果并用回车键选择。
  • 仅在输入预定义的最小字符数量后才进行AJAX调用。
  • 停止触发AJAX调用的某些键。

这采用了@ friek108的答案,超时& ajax呼叫取消功能。你可能想先检查一下。

ajaxAutoComplete({inputId:'autocomplete-input',ajaxUrl:'/search/my-auto-complete-results'}) 

function ajaxAutoComplete(options) 
{ 

    var defaults = { 
     inputId:null, 
     ajaxUrl:false,  
     data: {}, 
     minLength: 3 
    }; 

    options = $.extend(defaults, options); 
    var $input = $("#" + options.inputId); 


    if (options.ajaxUrl){ 


     var $autocomplete = $('<ul id="ac" class="autocomplete-content dropdown-content"' 
      + 'style="position:absolute"></ul>'), 
     $inputDiv = $input.closest('.input-field'), 
     request, 
     runningRequest = false, 
     timeout, 
     liSelected; 

     if ($inputDiv.length) { 
      $inputDiv.append($autocomplete); // Set ul in body 
     } else { 
      $input.after($autocomplete); 
     } 

     var highlight = function (string, match) { 
      var matchStart = string.toLowerCase().indexOf("" + match.toLowerCase() + ""), 
      matchEnd = matchStart + match.length - 1, 
      beforeMatch = string.slice(0, matchStart), 
      matchText = string.slice(matchStart, matchEnd + 1), 
      afterMatch = string.slice(matchEnd + 1); 
      string = "<span>" + beforeMatch + "<span class='highlight'>" + 
      matchText + "</span>" + afterMatch + "</span>"; 
      return string; 

     }; 

     $autocomplete.on('click', 'li', function() { 
      $input.val($(this).text().trim()); 
      $autocomplete.empty(); 
     }); 

     $input.on('keyup', function (e) { 

      if (timeout) { // comment to remove timeout 
       clearTimeout(timeout); 
      } 

      if (runningRequest) { 
       request.abort(); 
      } 

      if (e.which === 13) { // select element with enter key 
       liSelected[0].click(); 
       return; 
      } 

      // scroll ul with arrow keys 
      if (e.which === 40) { // down arrow 
       if (liSelected) { 
        liSelected.removeClass('selected'); 
        next = liSelected.next(); 
        if (next.length > 0) { 
         liSelected = next.addClass('selected'); 
        } else { 
         liSelected = $autocomplete.find('li').eq(0).addClass('selected'); 
        } 
       } else { 
        liSelected = $autocomplete.find('li').eq(0).addClass('selected'); 
       } 
       return; // stop new AJAX call 
      } else if (e.which === 38) { // up arrow 
       if (liSelected) { 
        liSelected.removeClass('selected'); 
        next = liSelected.prev(); 
        if (next.length > 0) { 
         liSelected = next.addClass('selected'); 
        } else { 
         liSelected = $autocomplete.find('li').last().addClass('selected'); 
        } 
       } else { 
        liSelected = $autocomplete.find('li').last().addClass('selected'); 
       } 
       return; 
      } 

      // escape these keys 
      if (e.which === 9 ||  // tab 
       e.which === 16 ||  // shift 
       e.which === 17 ||  // ctrl 
       e.which === 18 ||  // alt 
       e.which === 20 ||  // caps lock 
       e.which === 35 ||  // end 
       e.which === 36 ||  // home 
       e.which === 37 ||  // left arrow 
       e.which === 39) {  // right arrow 
       return; 
      } else if (e.which === 27) { // Esc. Close ul 
       $autocomplete.empty(); 
       return; 
      } 

      var val = $input.val().toLowerCase(); 
      $autocomplete.empty(); 

      if (val.length > options.minLength) { 

       timeout = setTimeout(function() { // comment this line to remove timeout 
        runningRequest = true; 

        request = $.ajax({ 
         type: 'GET', 
         url: options.ajaxUrl + val, 
         success: function (data) { 
          if (!$.isEmptyObject(data)) { // (or other) check for empty result 
           var appendList = ''; 
           for (var key in data) { 
            if (data.hasOwnProperty(key)) { 
             var li = ''; 
             if (!!data[key]) { // if image exists as in official docs 
              li += '<li><img src="' + data[key] + '" class="left">'; 
              li += "<span>" + highlight(key, val) + "</span></li>"; 
             } else { 
              li += '<li><span>' + highlight(key, val) + '</span></li>'; 
             } 
             appendList += li; 
            } 
           } 
           $autocomplete.append(appendList); 
          }else{ 
           $autocomplete.append($('<li>No matches</li>')); 
          } 
         }, 
         complete: function() { 
          runningRequest = false; 
         } 
        }); 
       }, 250);  // comment this line to remove timeout 
      } 
     }); 

     $(document).click(function() { // close ul if clicked outside 
      if (!$(event.target).closest($autocomplete).length) { 
       $autocomplete.empty(); 
      } 
     }); 
    } 
} 

而是通过一个附加效果的自动完成构件之一,我已经连同一个单一的,长的字符串追加所有这些,使这一进程更快。 (阅读jQuery .append()方法here)的精彩分析。

相关问题