Angel Politis Angel Politis - 6 months ago 22
Ajax Question

How to cancel an AJAX request when a new one is sent?

I know that similar questions have been asked before, but despite having read enough of them, I haven't managed to solve my problem.

I am creating a username input and I use AJAX to retrieve a response from the server depending upon the username being already used or not.




My JavaScript code:



var timer = null;
var passed4Before = false;
var xhttp = null;
var ajaxInProgress = false;
var username = document.getElementById("username");

username.onkeyup = function(e) {

// Check if username exists in the database
function usernameExists(value) {
if (keypressed.match(/[a-z0-9-_]/gi) || e.which === 8 || e.which === 46) {
clearTimeout(timer);
ajaxInProgress = true;
timer = setTimeout(function() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (xhttp.readyState === 4 && xhttp.status === 200) {
document.getElementById("div").innerHTML = xhttp.responseText;
}
};
xhttp.open("POST", "php.php", true);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send("username=" + value);
}, 1500);
}
};

if (this.value.length >= 4) {
// Check if user has typed above 4 characters
passed4Before = true;
}

// AN ATTEMPT TO ABORT THE AJAX REQUEST WHILE IT HAS STARTED THAT HAS FAILED
// RESULT: THE AJAX DOESN'T WORK AT ALL
if (ajaxInProgress) {
xhttp.abort();
ajaxInProgress = false;
}


if (this.value.length < 4) {
if (passed4Before) {
console.log("The username cannot be less than 4 characters");
passed4Before = false;
// To stop ajax request of the previous key press (if it hasn't started yet)
clearTimeout(timer);
}
} else {
usernameExists(this.value);
}
};






I am 100% sure that I somehow have to use xhttp.abort(), but I haven't found out yet.

I am using the ajaxInProgress variable to determine whether there is an active AJAX request and if there is, when I type again, it must stop and check the new value of my input.

The code in its current form does not accomplish that, but instead, it either never sends out an AJAX request or it sends one and then stops.

I would prefer a solution in JavaScript without any third-party plugins. Any help would be greatly appreciated.





[SOLVED] (Included Gilad Artzi's answer):



To anyone who may need that in the future here is the edited function:

function usernameExists(value) {
if (keypressed.match(/[a-z0-9-_]/gi) || e.which === 8 || e.which === 46) {
if (xhttp) {
xhttp.abort();
}
xhttp = new XMLHttpRequest();
clearTimeout(timer);
timer = setTimeout(function() {
xhttp.onreadystatechange = function() {
if (xhttp.readyState === 1) {
document.getElementById("loader1").innerHTML = "<img src = \"../../Content/Images/ajax-loader.gif\"/>";
}
else if (xhttp.readyState === 4 && xhttp.status === 200) {
document.getElementById("loader1").innerHTML = "<img class = \"invisible\" src = \"../../Content/Images/ajax-loader.gif\"/>";
document.getElementById("tip1").innerHTML = xhttp.responseText;
if (xhttp.responseText.indexOf("unavailable") > 0) {
username_label.style.color = "red";
}
else {
username_label.style.color = "green";
}
}
};
xhttp.open("POST", "Register.php", true);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send("username=" + value);
}, 1500);
}
};

Answer

You should keep a reference to your active XMLHttpRequest, and in case you fire a new one, use the abort method on the previous one.

To be more specific, in your code, declare the xhttp var in the top instead of inside the setTimeout callback, and before creating a new XHR (xhttp = new XMLHttpRequest();) simply abort the previous one, if exists:

if (xhttp) {
    xhttp.abort();
}
xhttp = new XMLHttpRequest();