Reputation: 3101
Attached Event handler to callback like :
$("someSelector").on('click',callBackHandler);
function callBackHandler(){
//Some code
$.ajax({
//Ajax call with success methods
})
}
My success method is manipulating some object properties. Since ajax is involved, it will not wait for the completion and next event handling will start. How can I make sure next click event handling starts only when previous handling is done.
Cannot think of a way of using deferred manually on this because I am triggering event manually on base of some condition in for loop (Not a clean style of coding, but has no other option in particular use case).
$('someSelector').trigger('click');
Upvotes: 0
Views: 1168
Reputation: 11600
var requestDataButton = document.querySelector('.js-request-data');
var displayDataBox = document.querySelector('.js-display-data');
var displayOperationsBox = document.querySelector('.js-display-operations');
var displayNumberOfRequestsToDo = document.querySelector('.js-display-number-of-requests-to-do');
var isAjaxCallInProgress = false;
var numberOfAjaxRequestsToDo = 0;
var requestUrl = 'http://jsonplaceholder.typicode.com/photos';
requestDataButton.addEventListener('click', handleClick);
function handleClick() {
displayNumberOfRequestsToDo.innerText = numberOfAjaxRequestsToDo;
numberOfAjaxRequestsToDo++;
if(!isAjaxCallInProgress) {
isAjaxCallInProgress = true;
requestData();
}
}
function handleResponse(data) {
displayData(data);
displayOperationsBox.innerHTML = displayOperationsBox.innerHTML + 'request handled <br>';
numberOfAjaxRequestsToDo--;
displayNumberOfRequestsToDo.innerText = numberOfAjaxRequestsToDo;
if(numberOfAjaxRequestsToDo) {
requestData();
} else {
isAjaxCallInProgress = false;
}
}
function displayData(data) {
displayDataBox.textContent = displayDataBox.textContent + JSON.stringify(data[0]);
}
function requestData() {
var request = new XMLHttpRequest();
request.open('GET', requestUrl, true);
request.onload = function() {
if (this.status >= 200 && this.status < 400) {
var data = JSON.parse(this.response);
handleResponse(data);
} else {
// on error
}
};
request.onerror = function() {
// There was a connection error of some sort
};
request.send();
displayOperationsBox.innerHTML = displayOperationsBox.innerHTML + 'request sent <br>';
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="js-request-data">Request Data</button>
<div>
<h2>Requests wainting in a queue to be sent:
<span class="js-display-number-of-requests-to-do">
0
</span>
</h2>
</div>
<div>
<h2>Operations:</h2>
<div class="js-display-operations"></div>
</div>
<div>
<h2>Response Data:</h2>
<div class="js-display-data"></div>
</div>
edit
here's a utility function that takes similar arguments as $.ajax, and then returns an augmented $.ajax function that keeps an eye on its previous calls and waits for all preceding requests to finish before dispatching another ajax call (are fired sequentially):
function sequentialize(requestData, responseHandler) {
let inProgress = false;
let deferredRequests = 0;
const makeRequest = () => {
$.ajax(requestData).then(processManager);
};
const processManager = (data) => {
responseHandler(data);
if (deferredRequests) {
deferredRequests--;
makeRequest();
} else {
inProgress = false;
}
};
return function () {
if (!inProgress) {
inProgress = true;
makeRequest();
} else {
deferredRequests++;
}
};
}
Upvotes: 0
Reputation: 6217
$("someSelector").on('click', function(event) {
event.preventDefault();
var urAjax = $.ajax({
// Ajax Call here...
});
urAjax.always(function(response) {
$.when( callBackHandler() ).done(function() {
// Handle your ajax response in here!
});
});
});
function callBackHandler() {
// Do Stuff
}
callBackHandler
function will fire, and when it's done, your ajax response for .always will fire directly after that. This allows for your ajax to load while the callBackHandler
function is running also, but doesn't fire the response until after the function is done! Hopefully I'm understanding what you are asking for here.
You can see an example jsfiddle located here: https://jsfiddle.net/e39oyk8q/11/
Try clicking the submit button multiple times before the AJAX request is finished, you will notice that it will loop over and over again the total amount of clicks you give it on the Submit button. You can see this by the amount of times the Alert box pops up, and also, it adds 100 to the len (that gets outputted on the page) during each call to the callBackHandler
function. So, I do believe this is what you asked for.
And, ofcourse, you can still use: $('someSelector').trigger('click');
EDIT
Another approach is to return a json object that can be used within the ajax call or wherever you need it within the click event, like so:
$("someSelector").on('click', function(event) {
event.preventDefault();
var myfunc = callBackHandler();
var urAjax = $.ajax({
type: 'POST',
url: myfunc['url'],
data: myfunc['data']
});
urAjax.always(function(response) {
$.when( myfunc ).done(function() {
console.log(myfunc['time']);
// Handle your ajax response in here!
});
});
});
function callBackHandler() {
var timestamp = new Date().getTime();
return { url: 'my_ajax_post_url', data: {data1: 'testing', data2: 'testing2'}, time: timestamp }
}
fiddle example here: https://jsfiddle.net/e39oyk8q/15/
Upvotes: 1
Reputation: 15846
You can remove the binding on the call of function and bind again when the ajax is done()
.
function callBackHandler(){
$("someSelector").off('click');
//Some code
$.ajax({
//Ajax call with success methods
}).done(function(){
$("someSelector").on('click',callBackHandler);
})
}
Upvotes: 0