awesomplete icon indicating copy to clipboard operation
awesomplete copied to clipboard

Any way to make ajax dynamic ?

Open vanilla38 opened this issue 9 years ago • 13 comments

Hi, I managed to get youtube results autocomplete using JSONP like that:

function jsonp(url, callback) {
var callbackName = 'jsonp_callback_' + Math.round(100000 * Math.random());
window[callbackName] = function(data) {
    delete window[callbackName];
    document.body.removeChild(script);
    callback(data);
};

var script = document.createElement('script');
script.src = url + (url.indexOf('?') >= 0 ? '&' : '?') + 'callback=' + callbackName;
document.body.appendChild(script);
}

jsonp('http://suggestqueries.google.com/complete/search?hl=en&q=MYQUERY&client=youtube', function(data) {
    var list = [];
    for (var i = 0; i < data[1].length; i++) {
        list.push(data[1][i][0]);
    }
    console.log(list);
    new Awesomplete(document.querySelector("#search"),{list:list});
});

But there's a little problem, I want MYQUERY to change on keypress and this way, reload the list content with new data. Is this possible ? Thanks.

vanilla38 avatar Dec 22 '15 16:12 vanilla38

I also need this, change data on keypress

kmsaglus avatar Mar 02 '16 10:03 kmsaglus

The page at https://www.sitepoint.com/javascript-autocomplete-widget-awesomplete/ seems to describe how this can be done with Awesomplete. Look at the section at the bottom called "The Finale".

centic9 avatar Jun 22 '16 10:06 centic9

The last AJAX example from Sitepoint breaks the key events, for instance, try selecting something by pressing up and down, it'll always come back to the first selection.

chhuang avatar Sep 30 '16 04:09 chhuang

I have the same issue as @chhuang described. My objective is to fetch new results from Elasticsearch, as more characters are typed into the field, gradually refining the list of suggestions. Retrieving all the data at once is not an option, because the database where I search contains tens of thousands of entries.

ralienpp avatar Oct 03 '16 11:10 ralienpp

I'm not sure if this is the right solution, what I did to temporary fix the problem was to stop the ajax call manually if the pressed key is arrow, esc or enter:

$(input).on('keyup', function(e) {
  var isReservedKey = (function() {
    var code = (e.keyCode || e.which);  

    // Arrows, Esc, Enter
    return code === 37 || code === 38 || code === 39 || code === 40 || code === 27 || code === 13
  })();

  // Only make the ajax call if key is not arrow, esc or enter
  !isReservedKey && _ajaxCall();
});

chhuang avatar Oct 03 '16 11:10 chhuang

I understand the idea, but it has a side-effect in my case - the input field is losing focus after each key event.

I then call document.getElementById('my-id').focus(); to explicitly set the focus back to my element - but it acts as if nothing happened, i.e. the focus is not restored.

ralienpp avatar Oct 03 '16 17:10 ralienpp

@ralienpp I implemented dynamic lists with ajax and I had no focus problem. You can't loose focus because of an ajax call!Either you perform dom manipulation in your ajax call or you loose focus because of breakpoints/debugger stuffs. Anyway, trying to get focus again cant resolve since caret would appear in a different position. Anyway a find thus software fantstic: simple and easy to customize, I was able also to cache ajax retrieved items to avoid too many calls with just about 20 lines of code.

frankabbruzzese avatar Oct 03 '16 21:10 frankabbruzzese

I agree that an AJAX call should not affect the focus in anyway, but nevertheless that is what I see. I produced a minimal example that exhibits this behaviour. As you can see, there's no other logic that is doing anything with the focus or with the keyboard input.

Note that the queries are sent to a local instance Elasticsearch, so you won't be able to actually run this example, but maybe it contains some obvious error that will help clarify this matter.

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="bower_components/awesomplete/awesomplete.css" />
</head>
<body>
    <section id="ajax-example">
    <h2>Type here</small></h2>
    <label class="">looking for: <input id='inp_name' class='inp' type="text"></label>
    <pre class="language-javascript"><code></code></pre>
    </section>
</html>

<script type="text/javascript" src='bower_components/jquery/dist/jquery.js' ></script>
<script type="text/javascript" src='bower_components/awesomplete/awesomplete.min.js' async></script>


<script type="text/javascript" src='index.js' ></script>

And this is the JS code

var list_name = null;

function run_elasticSearch (value){
    console.log('test');
    var ajax = new XMLHttpRequest();
    value = value+"*";
    ajax.open("GET", "http://127.0.0.1:9200/db/_search?q=name:"+value, true);
    ajax.onload = function() {
        values =  JSON.parse(ajax.responseText);
        list = values.hits.hits;
        list_name = list.map(function(i) { 
            return i._source.name; });
        console.log(list_name);
        new Awesomplete(document.querySelector("#ajax-example input"),{ list: list_name });

    };
    ajax.send();
    // document.getElementById('inp_name').focus();

}

$('#inp_name').on('keyup', function(e) {
  var value = $('#inp_name').val();
  console.log(value);
 var code = (e.keyCode || e.which);  
     // Arrows, Esc, Enter
 if (code === 37 || code === 38 || code === 39 || code === 40 || code === 27 || code === 13)
 {
    console.log('reserved');
 }
 else{
    console.log('not reserved');
    run_elasticSearch(value);
    // document.getElementById('inp_name').focus();
  }
});

Any assistance will be greatly appreciated.

ralienpp avatar Oct 03 '16 21:10 ralienpp

@ralienpp I think that's because you are creating a new instance of Awesomplete everytime you hit a key. Try setting up Awesomplete before your ajax call and outside your keyup event, and then just update list inside the the ajax call.

  var awesomeStuff = new Awesomplete(document.querySelector("#ajax-example input"));

  function run_elasticSearch (value){
    ...
    ajax.onload = function() {
      values =  JSON.parse(ajax.responseText);
      list = values.hits.hits;
      list_name = list.map(function(i) { 
      return i._source.name; });
      console.log(list_name);

      awesomeStuff.list = list_name;
    };
    ...
  }

chhuang avatar Oct 03 '16 22:10 chhuang

An alternative to the solution above:

In my case, I simply check if the input text changed (since navigation/losing focus won't change the text, it automatically takes care of this little gotcha).

I think this issue can be closed

Secretmapper avatar Nov 09 '16 16:11 Secretmapper

@chhuang and @ralienpp noticed that the keyCode block should really be AND instead of OR for the different keystrokes, otherwise it fires the AJAX when using the arrows.

if (code !== 37 && code !== 38 && code !== 39 && code !== 40 && code !== 27 && code !== 13) { ... }

stephenkeable avatar May 22 '17 14:05 stephenkeable

//this worked for me

function keyupHandler(e) {

       var code = (e.keyCode || e.which);      
        if (code === 37 || code === 38 || code === 39 || code === 40 || code === 27 || code === 13) {    
          //reserved 
            console.log(code);                
        } else {
            var murl = '/ajax/getItems?&itemmatch='+this.value;
            ajax.onreadystatechange = function() {                    
                if (this.readyState == 4 && this.status == 200) {
                    console.log('success');   				
                    var data = JSON.parse(this.responseText);				 
                    var list = [];                                                                                 
                    for (var i=0; i<data.length; i++) {
                      list.push(data[i].value,data[i].text)
                    }                        
                    console.log(list)
                    awesomplete.list = list
                    
                } else {    
                    console.log('error');    
                }
            }
            ajax.open("GET", murl, true);
            ajax.send(); 
        }
    

}

fredericorodrigues avatar Aug 31 '17 07:08 fredericorodrigues

Isn't this a perfect solution?

https://github.com/LeaVerou/awesomplete/issues/16892#issuecomment-223066074

var a = new Awesomplete(myInput, myOptions);
myInput.addEventListener('input', function() {
    var list = getNewListWithAjax();
    a.list = list;
    a.evaluate();
});

mercmobily avatar Oct 05 '18 22:10 mercmobily