2016-08-01 2 views
4

Я пытаюсь объединить команду materializecss autocomplete plugin с моим вызовом ajax, чтобы динамически загружать данные в соответствии с тем, что вводится в поле ввода.Как использовать материализовать плагин autocomplete с ajax?

Мой запрос ajax вызывается внутри события keydown. Все полученные данные автоматически вставляются в массив объектов/значений.

Затем я помещаю функцию автозаполнения в функцию успеха ajax, а значение ключа «data» - это массив объектов, построенный ранее.

Кажется, что я нахожусь на хорошем пути, но когда я тестирую в браузере, каждый раз, когда я что-то печатаю, раскрывающийся список предложений отображается как ожидалось с результатами, но вместо того, чтобы обновляться после каждого нажатия клавиши, предыдущий и так один ...

Итак, это моя проблема: как это сделать, чтобы избежать появления списка вариантов выпадающего списка, а вместо того, чтобы обновлять его каждый раз, когда я нажимаю клавишу?

Благодарим за помощь.

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 
    }, 

Ok. Вы скорректировали скобки и все еще имеете проблему. Сначала я скажу, что мне непонятно, почему вы пытаетесь повторно инициализировать виджет автозаполнения новыми данными каждый раз, когда пользователь нажимает клавишу. Я бы инициализировал его, когда открываю страницу, а затем, если есть изменения в данных, я бы повторно инициализировал их. Доступные выборы не будут меняться в результате нажатия пользователем клавиши.

Но это в стороне: глядя на документ, это довольно отрывочно, и вы сделали то, что он вам говорит. Он не рассматривает возможность повторной инициализации существующего виджета новыми данными. Вероятно, вам придется найти способ удалить предыдущий список перед повторной инициализацией. Вот то, что они говорят об их Select виджете:

Если вы хотите обновить элементы внутри избранного, просто повторите код инициализации сверху после редактирования оригинала выберите. Или вы можете уничтожить выбор материала с помощью этой функции ниже и создать новый выбор в целом.

Возможно, это относится и к виджету autocomplete, и они просто не смогли его документировать. Итак, я хотел бы попробовать это первым:

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

разрушает существующее автозаполнение, а затем повторной инициализацию с новыми данными. Если это не сработает (они не говорят, что они поддерживают метод автозаполнения , но вы никогда не знаете, пока не попытаетесь), тогда вам нужно будет выкопать в DOM, найти элемент, который хранит данные, и напишите код, чтобы удалить его, прежде чем вы вызовете функцию autocomplete(). Если это не удается, вы можете использовать автозаполнение jquery-ui, поскольку гораздо больше людей использует его, чем тот, который вы используете, и вы можете получить лучшую помощь.

+0

Спасибо.Однако всегда одна и та же проблема. список dropdow дублируется каждый раз, когда я нажимаю клавишу вниз, и есть несколько выпадающих списков, перекрывающих –

+0

Итак, вы скорректировали скобки и все еще имеете проблему? – BobRodes

+0

Да, я зафиксировал скобки и точки с запятой. Тем не менее та же проблема –

3

Здесь вы идете, гораздо более чистый пример.

  • Он основан на оригинальной функции Materialized.js
  • отменяет существующие запросы Ajax, как вы типа, так что вы не получите двойные результаты
  • Если удалить «тайм-аут» прокомментировал строки, это будет вызывать только после нажатия клавиши после вызова «x» истекает время вызова 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

Немного поздно на вечеринку, но подумал, что это может помочь некоторым людям, борющимся с одной и той же проблемой.

Один из способов, который я нашел, заключался в том, чтобы сделать копию объекта, возвращенного автозаполнением(), а затем использовать встроенную функцию 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.

Это принимает тайм-аут & функции отмены вызова ajax от ответа @ friek108. Сначала вы можете проверить это.

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).

Смежные вопросы