I am trying to have a loop that asks the user for a confirmation before doing a synchronous ajax request and it is not working in order. This is my code:
<script>
$(document ).ready(function() {
for(var i = 0; i < 3; i++) {
alert("iteration "+i);
$(".demo").easyOverlay("start");
$.ajax({
async: false,
url: "http://rest-service.guides.spring.io/greeting"
}).then(function(data) {
$('.demo').append(data.id);
$('.demo').append(data.content);
$(".demo").easyOverlay("stop");
});
}
});
</script>
The behaviour I am having with my code is like this:
Ask for the first confirmation.
Ask for the second confirmation.
Ask for the third confirmation.
Executed the three ajax calls one after the other.
It looks like for some reason all the ajax calls gets delayed until the alerts are all confirmed and I don't know why. I tried to achieve my same goal without using a loop and by repeating the code 3 times and I get the same exact strange behaviour.
Edit:
If i put the following line in 'then()' to check if the html is actually modified I can see in the console that the things actually happens in order and they just don't appears in the browser until I confirm every alert and that's what gives the impression that the order of execution is not correct. So I need to figure out why reflecting the changes done to the html is delayed and is not done immediately.
console.log($('.demo').html());
IMO jQuery.Deferred() object will be the most promising way.
The Deferred object, is a chainable utility object created by calling the jQuery.Deferred() method. It can register multiple callbacks into callback queues, invoke callback queues, and relay the success or failure state of any synchronous or asynchronous function.
deferred objects can be used for processing asynchronous events - you initiate an action and then register a callback which will be invoked when the action has completed. This includes AJAX, although there are plenty of other uses too.
Where asks for resolved
function callAjaxMethod(url, step) {
return $.Deferred(function() {
//Confirm box for use inputs
if(confirm(step))
{
//Ajax call
$.ajax(url).done(function(data){
//Do something
//Update your HTML if needed
});
}
setTimeout(function() {
//This will resolve your call again
this.resolve();
}.bind(this), 1000);
})
}
Deferred object
var defer = $.Deferred().resolve();
var counters = [1, 2, 3, 4, 5];
$.each(counters, function(key, value) {
defer = defer.then(function() {
return callAjaxMethod('URL', value);
});
});
It will call when all done
defer.then(function() {
//It will call when all done
});
Few of the documentation
Official jQuery.Deferred
Call ajax via jQuery deferred's
Article on Multiple jQuery promises
Hope this helps you :)
var $demo = $('#demo');
var ajaxURL = 'https://jsonplaceholder.typicode.com/posts';
function callAjaxMethod(url, step) {
return $.Deferred(function() {
//Confirm box for user inputs
if(confirm(step))
{
//Ajax call
$.ajax(url).done(function(data){
//Do something
//console.log(data);
//Update the HTML OK
$demo.append(step + ": Success" + "<br/>");
});
}
else
{
//Update the HTML when cancel
$demo.append("<font color='red'>"+ step +": Cancelled </font>" + "<br/>");
}
//Use timeout to get the resolved
setTimeout(function() {
this.resolve();
}.bind(this), 1000);
})
}
//Defer object
var defer = $.Deferred().resolve();
var counters = ['call 1', 'call 2', 'call 3', 'call 4', 'call 5'];
//Loop your calls
$.each(counters, function(key, value) {
defer = defer.then(function() {
return callAjaxMethod(ajaxURL, value);
});
});
defer.then(function() {
//It will call when all done
$(demo).append("<br/><br/>"+"ALL DONE");
});
div
{
color: blue;
font-size: 14px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="demo"></div>
That is because you should do the looping inside the Ajax request callback.
When you do it this way, the whole code is executed in a synchronic manner, whilst if you were to do so when the Ajax request callback is invoked, the requests and alerts would be executed like you would expect.
Edit:
Here is an example: (generic, you can customize it to your needs)
do(3)
function do(i) {
if (i === 0) return
$.ajax({...}).then(function() {
alert(...)
do(i-1)
})
}
Everytime ajax call fire it first ask for confirmation. If you allow then only ajax call fire and call for next ajax call and ask for confirmation and so on..
Please check below snippet for more understanding.
//call first time
doAjax(1,3)
//Function to call ajax repeatedly
function doAjax(arrCount,maxCount)
{
if (confirm("iteration "+arrCount)) {
$.ajax({
url: 'myUrl',
type: "POST",
data: {
// data stuff here
},
success: function (data) {
arrCount++;
//Next ajax call when current ajax call has been finished.
if(arrCount<=maxCount){
doAjax(arrCount,maxCount);
}
}
});
}
}
Related
Im using the following function to call an ajax request, and fill certain corresponding divs with the response:
$( function() {
$(document).ready(function() {
var postData = "";
$.ajax( {
url : \'functions/ajax_api.php?\',
type : \'post\',
data : postData,
success : function( resp ) {
$(\'#id1\').html($(\'#id1\' , resp).html());
$(\'#id2\').html($(\'#id2\' , resp).html());
}
});
return false;
});
});
The function works fine. My question is how can I call it automatically every few seconds?
I tried using window.setTimeout(function, 3000) but I couldnt set it up correctly.
use setInterval(); instead of .setTimeout()
Let me help you a little bit with that
var interval , setItinterval; // just a variables you can change names
interval = function(){
// ajax code here
}
to run it .. use:
setItinterval = setInterval(interval , 3000);
to stop it .. use
clearInterval(setItinterval);
Make sure to read setInterval for more information.
For Complete answer and Last thing I want to say when using setInterval(); Its better to use visibilitychange to avoid server error , server load or something like that
document.addEventListener('visibilitychange',function(){
if(document.visibilityState == 'visible'){
// user view the page
}else{
// user not see the page
}
});
You can use setTimeout() or setInterval, but setInterval may result in multiple simultaneous ajax calls if those calls take too long to respond. That isn't a problem if you call setTimeout() in the ajax success callback.
To use setTimeout(), first wrap your ajax call in a function. You can then add a call to setTimeout() to the ajax success callback. You also need to call the function once to start of the looping.
$(function() {
function postData() {
var postData = "";
$.ajax({
url: 'functions/ajax_api.php?',
type: 'post',
data: postData,
success: function(resp) {
$('#id1').html($('#id1', resp).html());
$('#id2').html($('#id2', resp).html());
// Call postData again after 5 seconds.
setTimeout(function() { postData(); }, 5000);
}
});
}
// Call postDate the first time to start it off.
postData();
});
Note: With the call to setTimeout in the success callback, the cycle will break if an ajax call fails. You may want that, but if you want it to act more like setInterval, you can place the call to setTimeout in the complete callback.
Here's some example code that will do it (note that it runs the function when the document loads, and then starts the interval). You can always use clearInterval(refresh_interval) if you need to stop it.
var refresh_interval;
function update_content() {
$.ajax({
url : \'functions/ajax_api.php?\',
type : \'post\',
data : postData,
success : function( resp ) {
$(\'#id1\').html($(\'#id1\' , resp).html());
$(\'#id2\').html($(\'#id2\' , resp).html());
}
});
}
$(document).ready(function() {
update_content();
setInterval(update_content, 3000);
}
The relevant documentation for using intervals is here: https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval
Though you may want to look into Server Sent Events, it's probably a better solution for what you want.
I have comment system using live ajax php, and also include for vote system on that comment
Logic: when i post new comment, system will call ajax function with method post, and display response in above of textarea for comment, that response is include vote system (a class="with_unique_id"), but when i click that vote, it wont calling ajax function (nothing happend in browser console), whereas in current comment that displaying in above of new comment, it working fine.
This is my ajax code for vote
jQuery(document).ready(function($){
$(".voteMe").click(function() {
var voteId = this.id;
var upOrDown = voteId.split('_');
$.ajax({
type: "post",
url: "<?php echo base_url('blog/likepost');?>/"+upOrDown[0],
cache: false,
data:'voteId='+upOrDown[0] + '&upOrDown=' +upOrDown[1],
success: function(response){
try{
if(response=='true'){
var newValue = parseInt($("#"+voteId+'_result').text()) + 1;
$("#"+voteId+'_result').html(newValue);
document.getElementById('likeStatus_'+upOrDown[0]).innerHTML = 'Success';
$("#likeStatus_"+upOrDown[0]).show();
setTimeout(function() { $("#likeStatus_"+upOrDown[0]).hide(); }, 5000);
}else{
$("#likeStatus_"+upOrDown[0]).show();
document.getElementById('likeStatus_'+upOrDown[0]).innerHTML = 'Liked';
setTimeout(function() { $("#likeStatus_"+upOrDown[0]).hide(); }, 5000);
}
}catch(err) {
alert(err.message);
}
},
error: function(){
alert('Error while request..');
}
});
});
});
It took me a while to read your code, but I guess this is the root cause:
if(response=='true'){
var newValue = parseInt($("#"+voteId+'_result').text()) + 1;
$("#"+voteId+'_result').html(newValue);
document.getElementById('likeStatus_'+upOrDown[0]).innerHTML = 'Success';
$("#likeStatus_"+upOrDown[0]).show();
setTimeout(function() { $("#likeStatus_"+upOrDown[0]).hide(); }, 5000);
}
This line here:
$("#"+voteId+'_result').html(newValue);
That become the link you want to click again. Right?
If that is so, then you need to re-assign the event handler.
By replacing the DOM element, you have also removed the assigned event handler
PS: You code is very hard to read. It will be nightmare for you to maintain it.
i have fixed my code with adding same ajax code function in response of current ajax with different id.
thankyou
I have been trying to scroll the page to a dynamic div that is created by the an ajax call.
When #divnotifications div clicked (below), I make the first ajax call that adds the Post details, then within this ajax call, another ajax call is made to add the related comments to the div.
The part explained so far works great. Then, I use $.when().then() to scroll to a div item created based on the ajax calls. However, the page does not scroll to the element that was created by LoadCommentsForPost ajax call.
Did I get the logic of $.when().then() wrong?
$(document).on('click', '#divnotifications div', function (event) {
event.preventDefault();
$.ajax({
//other details
success: function (postid) {
$.when(DisplayPostWithFullDetails(postid)).then(function () {
//scroll to the content created by
//LoadCommentsForPost function nested
//inside DisplayPostWithFullDetails
});
}
});
});
function DisplayPostWithFullDetails(postId) {
$.ajax({
//other details
success: function (post) {
//The code to build the div to display the post -- working fine
LoadCommentsForPost(post.PostId);
}
});
}
function LoadCommentsForPost(postid) {
$.ajax({
//other details
success: function (response) {
var comments = JSON.parse(response);
DisplayComments(comments);//builds the div to display the comments - working fine
}
});
}
UPDATED CODE
After receiving some feedback, I ended up with the following code. However, it is still not working. It works only if I add some delay to make sure the div is loaded:
$(document).on('click', '#divnotifications div', function (event) {
event.preventDefault();
$.ajax({
//other ajax stuff
success: function (postid) {
DisplayPostWithFullDetails(postid).done(function () {
setTimeout(function () {
var scrollto = $("div[data-" + type.toLowerCase() + "displayform='" + relateditem + "']").offset().top;
$("html, body").animate({ scrollTop: scrollto }, 600);
}, 500);
});
}
});
});
function DisplayPostWithFullDetails(postId) {
jQuery.support.cors = true;
return $.ajax({
//other ajax stuff
success: function (post) {
post = JSON.parse(post);
//display the post details
LoadCommentsForPost(post.PostId);
}
});
}
function LoadCommentsForPost(postid) {
var promise = new $.Deferred();
jQuery.support.cors = true;
$.ajax({
//other ajax stuff
success: function (response) {
var comments = JSON.parse(response);
DisplayComments(comments);//this is not ajax
promise.resolve('loadedcomments');
}
});
return promise;
}
Did I get the logic of $.when().then() wrong?
Yes, you need to return a promise from the functions if you want to use the function with $.when:
function DisplayPostWithFullDetails(postId) {
return $.ajax({...
// ^^^^^^
That said, wrapping a single promise in $.when is useless.
$.when(DisplayPostWithFullDetails(postid)).then(function () {
should just be:
DisplayPostWithFullDetail(postid).then(function () {
Did I get the logic of $.when().then() wrong?
No, but you are NOT returning the promise so you can't use the promise functions like .then().
UPDATE:
I use $.when().then() to scroll to a div item created based on the ajax calls. However, the page does not scroll to the element that was created by LoadCommentsForPost ajax call.
For me this means that you need to wait that both ajax calls are resolved.
This fiddle show how it should work emulating the ajax call using setTimeout Fiddle.
Your code may look similar to:
function DisplayPostWithFullDetails(postId) {
var promise = new $.Deferred();
$.ajax({
//other details
success: function (post) {
//The code to build the div to display the post -- working fine
LoadCommentsForPost(post.PostId).then(function() {
promise.resolve();
});
}
});
return promise;
}
function LoadCommentsForPost(postid) {
return $.ajax({
//other details
success: function (response) {
var comments = JSON.parse(response);
DisplayComments(comments);//builds the div to display the comments - working fine
}
});
}
Now when you execute the function DisplayPostWithFullDetails it return a promise.
So you can use .then() method;
DisplayPostWithFullDetails(postid)).then(function () {});
or...
var promise = DisplayPostWithFullDetails(postid);
promise.then(function(data){});
Also the major advantage of use $.when() is that you can execute the .then() method when all the promises that you pass to it are resolved.
There are not need to use it when you are waiting for a single promise.
I'm writing a javascript function that should change the view of a postcard depending on which case is selected.
My problem is that the old values of the object "m_case" is getting used. If I press the button with class "case-btn" twice I get the right case selected in my postcard view. But I want it to be triggered when I press the button once.
I guess I have to do something like a callback function in the m_case.setCase() function call, but I can't get it working,
$('.case-btn').on('click', function() {
remove_active_state_from_cases();
m_case.setCase($(this).data('case'));
// Changes the view of the postcard
m_postcard.changeBackground(m_case.getPhoto());
m_postcard.changeMessage(m_case.getMessageText());
m_postcard.changeFullName(m_case.getFullName());
m_postcard.changeCountry(m_case.getCountry());
$(this).toggleClass('active');
});
The setCase() function
this.setCase = function(id) {
// Set ID
this.setID(id);
var that = this;
$.ajax({
url: 'get_case_by_id.php',
type: 'get',
dataType: 'json',
data: {id: that.getID() },
success: function(data) {
if(data.success) {
that.setFirstName(data.first_name);
that.setFullName(data.full_name);
that.setAdress(data.adress);
that.setCountry(data.country);
that.setStamp(data.stamp);
that.setPhoto(data.photo);
that.setSummary(data.summary);
that.setStory(data.story);
that.setMessageText(data.message_text);
that.setDefaultMessageText(data.default_message_text);
that.setMessageImg(data.message_img);
} else {
console.log('failure');
}
}
EDIT The problem might be in my AJAX call, I have to wait till the ajax have been called. but how do I continue the first flow when my Ajax is done and not before?
SOLUTION
I made it working by adding a callback parameter and calling that function in the ajaxs complete function.
$('.case-btn').on('click', function() {
remove_active_state_from_cases();
var that = this;
m_case.setCase($(this).data('case'), function() {
m_postcard.changeBackground(m_case.getPhoto());
m_postcard.changeMessage(m_case.getMessageText());
m_postcard.changeFullName(m_case.getFullName());
m_postcard.changeCountry(m_case.getCountry());
$(that).toggleClass('active');
});
});
// Sets the whole case from an id.
this.setCase = function(id, callback) {
// Set ID
this.setID(id);
var that = this;
$.ajax({
url: 'get_case_by_id.php',
type: 'get',
dataType: 'json',
data: {id: that.getID() },
success: function(data) {
if(data.success) {
that.setFirstName(data.first_name);
that.setFullName(data.full_name);
that.setAdress(data.adress);
that.setCountry(data.country);
that.setStamp(data.stamp);
that.setPhoto(data.photo);
that.setSummary(data.summary);
that.setStory(data.story);
that.setMessageText(data.message_text);
that.setDefaultMessageText(data.default_message_text);
that.setMessageImg(data.message_img);
} else {
console.log('fail big time');
}
},
complete: function() {
callback();
}
});
}
Your m_postcard.changeBackground and other calls should be in the success callback, or in another function that is called from the success callback, as those values aren't set till the async ajax call is done.
With the way your code is now the m_postcard.changeBackground and other calls are called immediately after your setCase function is done executing. This means your methods are executed before the data has arrived from the server
While the ajax is processing you probably should show a loading message on the screen to let the user know they have to wait till the processing is done. Show the message before calling the .ajax call and hide it in the success/error callbacks.
Any changes to the site content should be done from the success callback, ie changing active states, changing content, etc.
I have three different AJAX queries that I want to hit various services. When they've all come back (or timed out) I'd like them to call a function.
I can imagine lots of ways of doing this, like having an intermediate function count when all the requests have come in, but is there a beautiful solution?
jQuery allows you to do what you want. See
http://www.erichynds.com/jquery/using-deferreds-in-jquery/
Naturally this only works if you are using jQuery, or can use jQuery.
If you are using jQuery 1.5 or later, you can use the jQuery.when method. For example:
$.when($.ajax("/page1.php"),
$.ajax("/page2.php")).done(function(a1, a2) {
/* a1 and a2 are arguments resolved for the
page1 and page2 ajax requests, respectively */
var jqXHR = a1[2]; /* arguments are [ "success", statusText, jqXHR ] */
if ( /Whip It/.test(jqXHR.responseText) ) {
alert("First page has 'Whip It' somewhere.");
}
});
Otherwise, see the Promises/A design pattern.
You can accomplish this easily with jQuery using the complete callback
var checked = 0;
$(function() {
$.ajax({ url: "1st ajax", complete: function(){ checked++; Check(); }});
$.ajax({ url: "2nd ajax", complete: function(){ checked++; Check(); }});
$.ajax({ url: "3rd ajax", complete: function(){ checked++; Check(); }});
}
function Check() {
if (checked >= 3) {
// all 3 have been successfully completed or timedout
}
}
or using then() deferred object to call the sequentially:
$.get("1st ajax").then(function(){
$.get("2nd ajax").then(function(){
$.get("3rd ajax").then(function(){
// call something
});
});
});
or using then() deferred object to call them without waiting with Check() method:
$.get("1st ajax").then(function(){ checked++; Check(); });
$.get("2nd ajax").then(function(){ checked++; Check(); });
$.get("3rd ajax").then(function(){ checked++; Check(); });
Hmm, maybe you could have a boolean value set to true once the last function called is executed fully? I suppose that this would pose a problem if the functions are being executed asynchronously, though.