Reputation: 6697
Here is my code:
.
.
keydown: function(ev) {
clearTimeout( $(this).data('timer') );
if ( 'abort' in $(this).data('xhr') ) $(this).data('xhr').abort(); // error here
var xhr, timer = setTimeout(function() {
xhr = $.ajax({
url : '/files/tags_autocomplete.php',
dataType : 'JSON',
success : function (tags) {
$("ul").html(tags.output);
}
});
}, 500);
$(this).data({timer : timer, xhr : xhr});
}
.
.
As I've commented, third line throws this error:
Uncaught TypeError: Cannot use 'in' operator to search for 'abort' in undefined
How can I fix it?
Upvotes: 2
Views: 26803
Reputation: 14649
The issue here is that the undefined
value does not have any properties. You need to perform a check on the return value of data()
to check that it isn't undefined.
var xhr = $(this).data('xhr');
if(typeof xhr !== 'undefiend' && xhr.abort) {
// do your code here
}
Replace your if
statement with the above 4 lines of code.
Upvotes: 4
Reputation: 19372
Change from:
if ('abort' in $(this).data('xhr') ) $(this).data('xhr').abort();
to:
if ($(this).data('xhr') && $(this).data('xhr').abort) {
$(this).data('xhr').abort();
}
Problem was simply checking if object has xhr
element. By default it does not exist so it's undefined
, and you were asking JS engine to find an element in undefined
information that was causing error.
So that's why I added to check if it has .data('xhr')
because for JS undefined
is treated as false
and after that I checked if data('xhr')
has abort
attribute.
By the way if you want to stop timer when key is pressed it's better to just clear timeout and it will not run AJAX call, so no need to put XHR object to element's data storage:
if($(this).data('timer')) {
clearTimeout($(this).data('timer'));
}
var timer = setTimeout(function() {
$.ajax({
url : '/files/tags_autocomplete.php',
dataType : 'JSON',
success : function (tags) {
$("ul").html(tags.output);
}
});
}, 500);
$(this).data('timer', timer);
or even simpler (without data storage):
if(window.autocompleteTimer) {
clearTimeout(window.autocompleteTimer);
}
window.autocompleteTimer = setTimeout(function() {
$.ajax({
url : '/files/tags_autocomplete.php',
dataType : 'JSON',
success : function (tags) {
$("ul").html(tags.output);
}
});
}, 500);
Upvotes: 2
Reputation: 318242
The issue is that if the user types again before 500ms has passed, $(this).data('xhr')
would be undefined, as it's not yet set to the ajax request.
As we can't use the in
operator on undefined
, only on objects, the correct solution to both clear the timeout and abort any pending requests, would be to just check if $(this).data('xhr')
has been set, and is an object, before checking if it has an abort
property
keydown: function(ev) {
var self = $(this);
clearTimeout(self.data('timer'));
if (typeof self.data('xhr') === 'object' && 'abort' in self.data('xhr')) {
self.data('xhr').abort();
}
var timer = setTimeout(function() {
self.data('xhr', $.ajax({
url: '/files/tags_autocomplete.php',
dataType: 'JSON',
success: function(tags) {
$("ul").html(tags.output);
}
}));
}, 500);
self.data('timer', timer);
Upvotes: 2