Reusable Ajax call in X times with same logic - javascript

This is very bad code
I need to do similar logic but without setInterval.
There is foundation 5 modal dialog
<span class="spanButton registration" data-reveal-id="addExternalRegistration">Add external registration</span>
This button that reveal empty modal
<div id="addExternalRegistration" class="reveal-modal" data-reveal aria-hidden="true">
and with jQuery I am fill dialog with form.
In Ajax success I change content in dialog if form has errors.
And story ends here. But I need to cover x submits before form is valid.
setInterval kills memory I know that, this is just example to show what I want.
response is new form with errors and should not be sumbited, it is need to send ajax request and all that in x circles.
$('.registration').click(function () {
$('#addExternalRegistration').load("/dashboard/add-external-registration/{{ confName }}");
setInterval(function () {
$('form[name="dashboard_conference_registration_form"]').on('submit', function (e) {
e.preventDefault();
$.ajax({
url: '/dashboard/add-external-registration/{{ confName }}',
method: 'POST',
data: $(this).serialize(),
success: function(response) {
$('#addExternalRegistration').html(response);
}
});
});
}, 3000);
});

I do some old tricks.
recursive calls
This is function that sends ajax request unlimited number of time
(in theory because of leak of memory, unfortunately).
var ajax = function () {
$('form[name="dashboard_conference_registration_form"]').on('submit', function (e) {
e.preventDefault();
$.ajax({
url: '/dashboard/add-external-registration/{{ confName }}',
method: 'POST',
data: $(this).serialize(),
success: function(response) {
$('#addExternalRegistration').html(function () {
return response;
});
setTimeout(ajax(), 2000);
}
});
});
};
Then I call recursive function that fires recursion on submit.
$('.registration').click(function () {
$('#addExternalRegistration').load("/dashboard/add-external-registration/{{ confName }}",
// Wait until form is loaded at modal window
// And then do the logic
function () {
$('form[name="dashboard_conference_registration_form"]').on('submit', function (e) {
e.preventDefault();
$.ajax({
url: '/dashboard/add-external-registration/{{ confName }}',
method: 'POST',
data: $(this).serialize(),
success: function(response) {
$('#addExternalRegistration').html(function () {
return response;
});
setTimeout(ajax(), 2000);
}
});
});
}
);
});

Related

how to stop a setInterval after I got my server response?

I'm trying to stop my setInterval() call. The best would be to identify whenever my AJAX request is fulfilled. So, If I got my AJAX GET response, then clearinterval().
$(document).on('submit', '#post-form', function(e) {
e.preventDefault();
$.ajax({
type: 'POST',
url: '/send',
data: {
room_name: $('#room_name').val(),
csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val(),
},
success: function(data) {
//alert(data)
}
});
$(document).ready(function com() {
loop = setInterval(function() {
$.ajax({
type: 'GET',
url: "/trafic",
success: function check(response) {
//SOME CODE//
},
error: function(response) {
//SOME CODE//
}
});
}, 1000)
setTimeout(clearInterval(loop), 10000);
})
});
I tried to set a timeout, but it is very imprecise as it may take longer/shorter than the delay. So I would need something like if GET successful {clear interval()}
You need to move the clearInterval() call into the success callback of the AJAX call. You'll also need to move the loop interval higher up in your code so that it can be referenced from the success callback.
I'm also not sure why the loop interval is wrapped in a $(document).ready() call, because you can be assured that the document is ready if it is submitted. Also, the variable loop is awfully ambiguous. Try using the name of the API endpoint instead, like traffic.
Try this code:
$(document).on('submit', '#post-form', function(e) {
e.preventDefault();
const traffic = setInterval(function() {
$.ajax({
type: 'GET',
url: "/trafic",
success: function check(response) {
clearInterval(traffic);
},
error: function(response) {
//SOME CODE//
}
});
}, 1000);
$.ajax({
type: 'POST',
url: '/send',
data: {
room_name: $('#room_name').val(),
csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val(),
},
success: function(data) {
// some code
}
});
});
Can I ask you first why did you use setInterval on this HTTP request ? You are probably using more computation power than you need.
You should probably make the request async (e.g https://petetasker.com/using-async-await-jquerys-ajax)
If you want to wait for an event to appear, you may want to have a look at web sockets (https://www.tutorialspoint.com/websockets/index.htm)

Why is my response data empty in the complete function of a jquery ajax call?

I have a function that fires two ajax calls when toggling a radio button. Both calls return a price and put it inside an element. The problem is when I spamclick the radiobutton, sometimes the prices differ from eachother while they should be the same, this means the ajax calls are out of synch with eachother.
I tried removing the part that appends the price from the success function to the complete function, so it only adds the result of the PHP scripts when the entire call is finished. But for some reason it won't append the price when I put it inside the complete function, why is that?
My function:
$('.checkoutwrap input[name=ontwerpcontrole]').on("change", function(e) {
e.preventDefault();
var productid = $(this).closest('.prodinfoleft').siblings('.prodinforight').find('.productid').val();
var $pricediv = $(this).closest('.prodinfoleft').siblings('.prodinforight').find('.prodinfoprice');
$.ajax({
type:'post',
url:"checkout/ontwerpcontrole.php",
data:({ontwerp: ontwerp, productid: productid}),
success:function(data){
},
complete: function(data) {
refreshcoupon(true);
}
});
$.ajax({
type:'post',
url:"checkout/prices.php",
data:({productid: productid}),
success:function(data){
},
complete: function(data) {
$($pricediv).empty().append( data );
}
});
});
Above puts no price in $pricediv, but when I put that part in the success function like this:
$('.checkoutwrap input[name=ontwerpcontrole]').on("change", function(e) {
e.preventDefault();
var productid = $(this).closest('.prodinfoleft').siblings('.prodinforight').find('.productid').val();
var $pricediv = $(this).closest('.prodinfoleft').siblings('.prodinforight').find('.prodinfoprice');
$.ajax({
type:'post',
url:"checkout/ontwerpcontrole.php",
data:({ontwerp: ontwerp, productid: productid}),
success:function(data){
},
complete: function(data) {
refreshcoupon(true);
}
});
$.ajax({
type:'post',
url:"checkout/prices.php",
data:({productid: productid}),
success:function(data){
$($pricediv).empty().append( data );
},
complete: function(data) {
}
});
});
The function used inside the first ajax call:
function refreshcoupon(force){
$.ajax({
type:'post',
url:"checkout/refreshcoupon.php",
data:({}),
success:function(data){
$( "body #coupon" ).empty().append( data );
}
});
}
It works fine (except like mentioned if you click to fast the prices are not the same).
Why is this?
You have couple of synced and couple of sequential ajax calls. Therefor it may happen that first request is done after last one. You probably have more solutions, but simply one would be to check if your variable productid is still same in ajax success function:
$('.checkoutwrap input[name=ontwerpcontrole]').on("change", function(e) {
e.preventDefault();
var $ontwerp = $(this).closest('.prodinfoleft').siblings('.prodinforight').find('.productid');
var productid = $ontwerp.val();
var $pricediv = $(this).closest('.prodinfoleft').siblings('.prodinforight').find('.prodinfoprice');
$.ajax({
type: 'post',
url: "checkout/ontwerpcontrole.php",
data: ({
ontwerp: ontwerp,
productid: productid
}),
success: function(data) {
if ($ontwerp.val() == productid) {
refreshcoupon($ontwerp, productid);
};
}
});
$.ajax({
type: 'post',
url: "checkout/prices.php",
data: ({
productid: productid
}),
success: function(data) {
if ($ontwerp.val() == productid) {
$($pricediv).empty().append(data);
};
}
});
});
function refreshcoupon($ontwerp, productid) {
$.ajax({
type: 'post',
url: "checkout/refreshcoupon.php",
data: ({}),
success: function(data) {
if ($ontwerp.val() == productid) {
$("body #coupon").empty().append(data);
};
}
});
}
Anyhow... looking at this code it does not look fine. Maybe try to do it with only one ajax call, save resources, reduce errors and debugging etc.

Rebind function when change DOM after ajax

I'm trying to get the height of an element before and after an ajax call to change the content of this element (for learning reasons).
Example:
$(document).ready()
calcHeigth('#listar-cursos');
});
funcion calcHeigth(idElement){
console.log($(idElement).outerHeight(true));
}
<div id="listar-cursos">all the content is here</div>
When the document is ready, calcHeigth function returns 200px.
There is a form on that page that is sent by ajax and when the request ends I just empty the contents of the element, and then call calcHeigth again (in ajaxComplete event).
$("#formSeacrh").submit(function () {
if ($(this).valid()) {
var url = $(this).attr("action");
var data = $(this).serialize();
$.ajax({
type: "POST",
url: url,
data: data,
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
success: function (data) {
$("#listar-cursos").html("");
},
complete: function () {
Completo();
},
beforeSend: function () {
Carregando();
},
error: function () {
Falha();
},
ajaxComplete: function () {
calcHeigth('#listar-cursos');
}
})
return false;
}
return false;
});
The result from calcHeigth is always 200px, like when the document is ready, even with the empty element. calcHeigth not realized that the element was changed. The result that I expected was 40px. How to fix and get the current height?
$("#formSeacrh").submit(function () {
if ($(this).valid()) {
var url = $(this).attr("action");
var data = $(this).serialize();
$.ajax({
type: "POST",
url: url,
data: data,
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
success: function (data) {
$("#listar-cursos").html("");
Completo();
calcHeigth('#listar-cursos');
},
beforeSend: function () {
Carregando();
},
error: function () {
Falha();
}
})
return false;
}
return false;
});
you only need 1 ready function, not 3. i hope this works now how you wish.
if you do your calc after your clear the html from the node, the height should be 0.
by the way. $('listar-cursos').empty() is better than .html("")

Prevent double submits form

I have a form which has a submit button. If I click this submit button then JSON will be posted to a webservice through AJAX:
$("#msform").submit(function (e) {
$.ajax({
url: 'https://example.com/webservice',
type: 'POST',
data: formData1,
crossDomain: true,
dataType: 'json',
jsonpCallback: 'callback',
success: function (data) {
console.log(data);
}
});
});
The webpage will also load and go to another page.. While loading the user can click multiple times on the Submit button, if he does that then for multiple times the AJAX post will be done to the webservice.
I tried this code to fix this but it does not work:
// jQuery plugin to prevent double submission of forms
jQuery.fn.preventDoubleSubmission = function () {
$(this).on('submit', function (e) {
var $form = $(this);
if ($form.data('submitted') === true) {
// Previously submitted - don't submit again
e.preventDefault();
} else {
// Mark it so that the next submit can be ignored
$form.data('submitted', true);
}
});
// Keep chainability
return this;
};
$('#msform').preventDoubleSubmission();
Any idea why double posting is not prevented??
The solution is to use a variable called wasSubmitted which verify if ajax request was already sent.
var wasSubmitted = false;
$("#msform").submit(function (e) {
if(!wasSubmitted) {
wasSubmitted = true;
$.ajax({
url: 'https://example.com/webservice',
type: 'POST',
data: formData1,
crossDomain: true,
dataType: 'json',
jsonpCallback: 'callback',
success: function (data) {
console.log(data);
}
});
return wasSubmitted;
}
return false;
});
I think a simple preventDefault would be enough
$("#msform").submit(function (e) {
e.preventDefault();
$.ajax(..)
The solution, that comes to my mind first, is to disable the button onclick with JS.
document.getElementById("btn_id").setAttribute("disabled","disabled");

Show a loading bar using jQuery while making multiple AJAX request

I have function making multiple AJAX request with jQuery like:
function() {
$.ajax({
url: "/url",
data: {
params: json_params,
output: 'json'
},
async: false,
success: function(res) {
data1 = res
}
});
$.ajax({
url: "/url",
data: {
params: json_params,
output: 'json'
},
async: false,
success: function(res) {
data2 = res;
}
return data1 + data2;
});
}
While this function is running and data is loading I want to display a loading image without blocking it.
I have tried showing the loading icon using ajaxSend ajaxComplete, but does not work, since I have multiple ajax calls.
I also tried showing the loading at the beginning of the function and hiding at the end of the function, but failed.
How to do this?
How exactly did you try loading? Using the ajaxStart/ajaxStop events on the elements is one way to accomplish what you want. It could look like this:
$('#loadingContainer')
.hide() // at first, just hide it
.ajaxStart(function() {
$(this).show();
})
.ajaxStop(function() {
$(this).hide();
})
;
Maybe this helps you, I often used this before and it works like a charm..
I think the answer is really a combination of several of these. I would begin with ajax start to show the loading image at 0 (or whereever you want the start to be). Then I would use a callback function to increment the loading bar and repaint it.
For example
//when ajax starts, show loading div
$('#loading').hide().on('ajaxStart', function(){
$(this).show();
});
//when ajax ends, hide div
$('#loading').on('ajaxEnd', function(){
$(this).hide();
});
function ajax_increment(value) {
//this is a function for incrementing the loading bar
$('#loading bar').css('width', value);
}
//do ajax request
$.ajax({
url:"", //url here
data: {params:json_params,output:'json'},
async: false,
success: function (res) {
data1=res
ajax_increment(20); //increment the loading bar width by 20
}
});
$.ajax({
url:"", //url here
data: {params:json_params,output:'json'},
async: false,
success: function (res) {
data1=res
ajax_increment($('loading bar').css('width') + 10); // a little more dynamic than above, just adds 10 to the current width of the bar.
}
});
You could try something like this: Define a callback with a counter, and the callback hides the image after it's been called the required number of times.
showLoadingImage();
var callbackCount = 0;
function ajaxCallback() {
++callbackCount;
if(callbackCount >= 2) {
hideImage();
}
}
$.ajax({
url:"/url",
data: {params:json_params,output:'json'},
async: false,
success: function (res) {
data1=res
ajaxCallback();
}
});
$.ajax({
url:"/url",
data: {params:json_params,output:'json'},
async: false,
success: function (res) {
data2=res;
ajaxCallback();
}
});
That's only necessary for asynchronous calls, though. The way you're doing it (all your AJAX calls are synchronous), you should be able to just call hideImage() before returning at the end of your outer function.
You should be able to bind to the start and then end with the following:
$('#loading-image').bind('ajaxStart', function() {
$(this).show();
}).bind('ajaxStop', function() {
$(this).hide();
});
Or you could use beforeSend and on Complete
$.ajax({
url: uri,
cache: false,
beforeSend: function() {
$('#image').show();
},
complete: function() {
$('#image').hide();
},
success: function(html) {
$('.info').append(html);
}
});

Categories