awesomplete
awesomplete copied to clipboard
Any way to make ajax dynamic ?
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.
I also need this, change data on keypress
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".
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.
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.
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();
});
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 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.
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 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;
};
...
}
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
@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) { ... }
//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();
}
}
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();
});