2016-08-01 83 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)的精彩分析。

相關問題