How to use materialize autocomplete plugin with ajax?

I am trying to combine a materializecss autocomplete plugin with my ajax call to dynamically load data according to what is being typed into the input field.

My ajax request is fired inside the keydown event. All data is automatically extracted to an array of objects / values.

Then I put the autocomplete function in the ajax success function, and the value of the "data" key is an array of objects built earlier.

I seem to be on a good path, but when I test in the browser, every time I type something, the dropdown menu offers the result, as expected, with the results, but instead of being updated after each key press, another drop-down list overlaps the previous one and so one ...

So, this is my problem: how to do to avoid the list of options from the drop-down list and instead of updating it every time I press a key?

Thanks for the help.

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

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

        }; 
	
		 $.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){
			
			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
	 
		
        },
        error: function(jqXHR, errorStatus, errorThrown){
          console.log(jqXHR);
          console.log(errorStatus);
          console.log(errorThrown);
        }

       }) 
		
Run code
+4
source share
5 answers

Here you are, a cleaner example.

  • It is based on the original Materialized.js function.
  • Cancels existing ajax requests as you type so that you don't get duplicate results.
  • If you delete the commented out lines of "timeout", it will only call ajax after the expiration of the time "x" after pressing the key. It can be useful when you type quickly to avoid ajax calls every time you press a key (even if they are canceled).

See below:

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
    });
  }
}
+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() ).

+3

, , , .

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

        $(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 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);
      	}

        $(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>
+1

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:

select, . .

, autocomplete, . , :

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

, . ( , destroy() , , ), DOM, , , , autocomplete(). , jquery-ui, , , , .

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;

and wherever I needed to use the autocomplete plugin, I did it.

 $('#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) {
    }
});
0
source

Source: https://habr.com/ru/post/1649731/


All Articles