javascript - execute function after for loop - javascript

I have a function where onclick a button will get all the id of selected task from a gantt chart and run a for loop to save each of the selected task i edited in a form using AJAX request.
The problem now on AJAX request success I add a code to clear and load all the data again in the gantt chart but it doesn't goes as intended, load the data several times and start creating duplicate of the same data in my gantt, I tried to execute the gantt.load function outside of the loop and it still not working.
So how can I create a condition where I reload the gantt AFTER the loop is finish executed? Any help is much appreciated thanks.
Below is my code :
HTML
<button type="button" class="btn btn-primary" onclick="editForm()">Edit</button>
javascript
function editForm() {
var selected_task = gantt.getSelectedTasks();
for (var i = 0; i < selected_task.length; i++) {
var task = selected_task[i];
var data = gantt.getTask(task);
$.ajax({
type: 'PUT',
url: '/api/dashboard/workorder_detail/' + data.workorder_id + '/',
data: postData,
success: function () {
$('#edit_form_modal').modal('hide');
gantt.clearAll();
gantt.load("/api/scheduler/{{ selected_project.id }}/?format=json", "json");
},
error: function (err) {
alert("Failed because of " + err);
}
})
}
}

Map selected tasks to a list of promises and use jQuery when to load the gantt after all the promises have resolved.
function editForm() {
var selected_task = gantt.getSelectedTasks();
var saveSelectedTask = selected_task.map(function(task, i) {
var data = gantt.getTask(task);
return $.ajax({
type: 'PUT',
url: '/api/dashboard/workorder_detail/' + data.workorder_id + '/',
data: postData,
});
});
$.when(saveSelectedTask)
.done(function() {
$('#edit_form_modal').modal('hide');
gantt.clearAll();
gantt.load("/api/scheduler/{{ selected_project.id }}/?format=json", "json");
})
.fail(function(err) {
alert("Failed because of " + err);
});
}

in this case, you should use Promise, exactly is Promise.all (I suggest you go to these URLs to learn more about Promise before implement.
The idea is letting the request run parallel, then wait for all finish and do your callback.
I will rewrite your JS to:
function editForm() {
var selected_task = gantt.getSelectedTasks();
Promise.all(selected_task.map(function(task) {
var data = gantt.getTask(task);
return $.ajax({
type: 'PUT',
url: '/api/dashboard/workorder_detail/' + data.workorder_id + '/',
data: postData,
})
}).then(function(results) {
$('#edit_form_modal').modal('hide');
gantt.clearAll();
gantt.load("/api/scheduler/{{ selected_project.id }}/?format=json", "json");
})
}
update: if you'd prefer to use jQuery function, then you can use $.when()
function editForm() {
var selected_task = gantt.getSelectedTasks();
$.when(selected_task.map(function(task) {
var data = gantt.getTask(task);
return $.ajax({
type: 'PUT',
url: '/api/dashboard/workorder_detail/' + data.workorder_id + '/',
data: postData,
})
}).then(function(results) {
$('#edit_form_modal').modal('hide');
gantt.clearAll();
gantt.load("/api/scheduler/{{ selected_project.id }}/?format=json", "json");
})
}
but as I said above, solve the problem doesn't make you better, should dig deep into it and learn how functions works.

Related

Multiple AJAX calls and show div on finish

I have a JS script doing multiple AJAX requests. First I'm requesting a product by ID and then I'm requesting every single variant of this product. I can't do any form of backend coding since the environment I'm working in is closed.
My requests works fine, but right now I'm appending every single variant to a div, and my client don't really like this, so I was thinking is it possible to load all data into a variable and then fade in the parent div of all variants at the very end?
My script looks like this:
var variants = $('.single_product-variant-images');
$.ajax({
url: productMasterURL,
success: function (data) {
$(data).find('Combinations Combination').each(function () {
var variantID = $(this).attr('ProductNumber');
$.ajax({
url: "/api.asp?id=" + escape(variantID),
dataType: "json",
async: true,
cache: true,
success: function (data) {
variants.append('<div class="variant"><img src="' + data.pictureLink + '" alt=""/></div>');
variants.find('.variant').fadeIn(300);
}
});
});
}
});
Some fast and dirty solution, but idea and concept of solution is clear. It is bad solution, but works for you in your case when you have no access to backend code.
var all_load_interval;
var is_all_data_ready = false;
var all_data_count = 0;
var variants = $('.single_product-variant-images');
$.ajax({
url: productMasterURL,
success: function (data) {
var data_count = $(data).find('Combinations Combination').length;
$(data).find('Combinations Combination').each(function () {
var variantID = $(this).attr('ProductNumber');
$.ajax({
url: "/api.asp?id=" + escape(variantID),
dataType: "json",
async: true,
cache: true,
success: function (data) {
// make div with class variant hidden
variants.append('<div class="variant"><img src="' + data.pictureLink + '" alt=""/></div>');
// count every variant
all_data_count += 1
if (all_data_count == data_count) {
// when all data got and created, lets trigger our interval - all_load_interval
is_all_data_ready = true;
}
}
});
});
}
all_load_interval = setInterval(function() {
// Check does all data load every second
if (is_all_data_ready) {
// show all div.variant
variants.find('.variant').fadeIn(300);
clearInterval(all_load_interval);
}
}, 1000);
});

Javascript loop with ajax call

I've been struggling all afternoon to understand how to make this work, hopefully someone can help. I have a simple requirement to run through a list of checked check boxes, retrieve some data from the server, fill an element with the data expand it. So far I have the following code;
function opentickedrows() {
$('input[type=checkbox]').each(function () {
if (this.checked) {
tid = $(this).attr('name').replace("t_", "");
$.ajax({
url: '/transfer_list_details_pull.php?id=' + tid,
type: 'GET',
success: function (data) {
$('#r' + tid).html(data);
$("#r" + tid).show();
$("#box" + tid).addClass("row-details-open");
}
});
}
});
}
The problem that I am having is that the ajax calls all seem to happen so fast that 'tid' isn't being updated in the ajax call. From what I have read I believe I need to wrap this up into a couple of functions with a callback but I just can not get my head around how. I'd be really grateful if someone can set me on the right path.
Ajax calls are asynchronous, so when the success callback is invoked, tid has the value of the last item of the $('input[type=checkbox]').
You could use a closure:
function opentickedrows() {
$('input[type=checkbox]').each(function () {
if (this.checked) {
tid = $(this).attr('name').replace("t_", "");
(function(tid) {
$.ajax({
url: '/transfer_list_details_pull.php?id=' + tid,
type: 'GET',
success: function (data) {
$('#r' + tid).html(data);
$("#r" + tid).show();
$("#box" + tid).addClass("row-details-open");
}
});
})(tid)
}
});
}

How to display a progress bar during an ajax request (jquery/php)

I have an ajax request, whereby I am installing a magento shop automatically, and when the process is done, it would redirect the user to the newly created shop. Here are my codes:
function postSuccessFormData() {
var targetUrl = '/index.php/install/wizard/successPost';
jQuery('.form-button').addClass('loading');
setInterval(installStatus(),4000);
jQuery.ajax({
url: targetUrl,
global: false,
type: 'POST',
data: ({
finish: 1,
password_key: jQuery('#password_key').val()
}),
async: true,
dataType: 'json',
error: function() {
alert("An error has occurred. Please try again.");
},
success: function(data) {
window.location.href = '/';
}
});
function installStatus() {
var installerUpdatesUrl = '/index.php/install/wizard/installerStatus';
//showProgressBar();
jQuery.ajax({
url: installerUpdatesUrl,
// global: false,
type: 'GET',
async: true,
dataType: 'json',
error: function (data) {
// alert(data.result);
},
success: function (data) {
handle data.result
var dataKeys = Object.keys(data);
var lastElementKey = dataKeys[dataKeys.length - 1];
var lastMessage = data[lastElementKey]['message'];
if(data[lastElementKey]['progress'] == '') {
updateProgressBar(data[dataKeys[dataKeys.length - 2]]['progress'],100);
}
setting message
jQuery("#message").html(lastMessage);
if (data[lastElementKey]['state'] == 'Failure') {
var stepStr = lastElementKey.split('_');
var stepString = stepStr[0].toUpperCase() + ' ' + stepStr[1] + ':';
alert(stepString + "\n" + data[lastElementKey]['message']);
//hideProgressBar();
jQuery('.form-button').removeClass('loading');
return false;
} else if (data[lastElementKey]['state'] == 'Finish') {
alert(data[lastElementKey]['message']);
//hideProgressBar();
jQuery('.form-button').removeClass('loading');
//window.location.href = '/';
} else {
// installStatus();
}
},
complete: function () {
installStatus();
jQuery('.form-button').removeClass('loading');
}
});
}
The way this is done:
After every 4 seconds the function installStatus is run, which will output the current progress in JSON format. My problem is, this function needs to be executed simultaneously with the function post().
This is not happening, the installStatus is only run after the first function has been completed.
What is wrong?
You are executing installStatus when you define it. So this:
setInterval(installStatus(),4000);
needs to be
setInterval(installStatus, 4000);
The new XMLHttpRequest has a nice progress event you can listen to show the user the upload progress.
Here's the spec with a nice demo: https://developer.mozilla.org/en/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Monitoring_progress
Initially you should call installStatus() only once and then inside the method inside ajax success you should update the procent in the progress bar and call it recursively the same method. On the server side you can save the current procent in a cookie and with every recursive call you can update the cookie and return the procent.

Display text or preloader before sending multiple ajax calls in a jQuery when, then function?

I have an array of multiple ajax calls inside a when then function and would like to display a preloder or a text before every call.
Let's say before every call I want to show:
"processing task id 1..." and when finished then
"processing task id 2..." and so on until the end that it's being cleared.
I tried to use beforeSend on the ajax call but always displays the first id which is 1.
any ideas?
var ids = [1, 2, 3, 4, 5]; // task ids
var deferreds = [];
//
$.each(ids, function(i, id_task){
deferreds.push(
$.ajax({
type: "POST",
url: '/tasks/import',
data: $.param({id_task: id_task}),
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
// always displaying "processing task id 1..."
beforeSend: function(){
$('#iter_msgs').html("processing task id " + id_task + "...");
}
//
})
.success(function(response){
// more stuff
})
);
});
//
$.when
.apply($, deferreds)
.done(function(a) {
//
$('#iter_msgs').html('')
});
So far I want to achieve the equivalent of the following but instead using when, then:
//
var id_task = 1;
$('#iter_msgs').html("processing task id " + id_task + "...");
//
$.ajax({
type: "POST",
url: '/tasks/import',
data: $.param({id_task: id_task}),
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})
.success(function(response) {
$('#iter_msgs').html("");
});

How do you stop a user from repeatedly clicking a jQuery AJAX call?

I have a web-page with the following script
Javascript
function LinkClicked() {
var stage = this.id;
var stop = $('#ContentPlaceHolderMenu_txtDate').val();
var nDays = $('#ContentPlaceHolderMenu_txtNumberOfDays').val();
$("[id$='spinner']").show();
$.ajax({
type: 'POST',
contentType: 'application/json',
url: "...",
data: "{stage:'" + stage + "',stop:'" + stop + "',nDays:'" + nDays + "'}",
success: function (data) {
$("[id$='spinner']").hide();
PlotData(data.d);
},
error: function () {
$("[id$='spinner']").hide();
alert("An error occured posting to the server");
}
});
}
How do I stop the user from repeatedly clicking whilst the query is running? The call is from a cell in a grid and can't easily be disabled. Ideally, I'd like a way of doing it in the script without disabling the link on the DOM.
Here I clicked five times, and you can see five AJAX requests are sent. The page should disable the same call being repeatedly invoked whilst it is already running.
Thanks in advance.
You could have an external variable tracking the state
var linkEnabled = true;
function LinkClicked() {
if(!linkEnabled){
return;
}
linkEnabled = false;
var stage = this.id;
var stop = $('#ContentPlaceHolderMenu_txtDate').val();
var nDays = $('#ContentPlaceHolderMenu_txtNumberOfDays').val();
$("[id$='spinner']").show();
$.ajax({
type: 'POST',
contentType: 'application/json',
url: "...",
data: "{stage:'" + stage + "',stop:'" + stop + "',nDays:'" + nDays + "'}",
success: function (data) {
$("[id$='spinner']").hide();
PlotData(data.d);
linkEnabled =true;
},
error: function () {
$("[id$='spinner']").hide();
alert("An error occured posting to the server");
linkEnabled = true;
}
});
}
This also has the advantage that you can choose to enable other effects of this function if you want, and only prevent the repeat ajax calls.
(Note that ideally you would want to stick the external variable in a closure or a namespace rather than making it a global).
Disable a button when user clicks it, and set disabled to false when you get response from ajax.
Declare a variable outside of the function with an initial value of false:
var pending = false;
When you make the request, you'd do:
if (pending == true) {return;}
pending = true;
This makes it stop if you're already running, and when the request is done:
pending = false;
Now even without a button, the request won't fire multiple times.
As a side note, your data doesn't need to be a string. You can just do:
data: {stage: stage, stop: stop, nDays: nDays}
you can just check use this
var ajax_stat = false
function doing_ajax(){
if(ajax_stat) return;
ajax_stat = true;
var xmlRequest = $.ajax({
type: 'POST',
contentType: 'application/json',
url: "...",
data: "{stage:'" + stage + "',stop:'" + stop + "',nDays:'" + nDays + "'}",
success: function (data) {
$("[id$='spinner']").hide();
PlotData(data.d);
},
error: function () {
$("[id$='spinner']").hide();
alert("An error occured posting to the server");
ajax_stat = false;
}
});
}
Use below code. it will not make multiple ajax calls.
function LinkClicked() {
if($(window).data("ajaxRUnning")){
return;
}
$(window).data("ajaxRUnning",true);
var stage = this.id;
var stop = $('#ContentPlaceHolderMenu_txtDate').val();
var nDays = $('#ContentPlaceHolderMenu_txtNumberOfDays').val();
$("[id$='spinner']").show();
$.ajax({
type: 'POST',
contentType: 'application/json',
url: "...",
data: "{stage:'" + stage + "',stop:'" + stop + "',nDays:'" + nDays + "'}",
success: function (data) {
$("[id$='spinner']").hide();
PlotData(data.d);
$(window).data("ajaxRUnning",false);
},
error: function () {
$("[id$='spinner']").hide();
alert("An error occured posting to the server");
$(window).data("ajaxRUnning",false);
}
});
}

Categories