AJAX requests inside a loop - javascript

I am trying to call multiple ajax requests inside a loop to load multiple dropdown lists. I tried the sequential way and i can see that the last item in loop only is getting filled with values
var targetcontrols = [];
var targetcontrols_array = targetControl.split(',');
var targetsourcecontrols = [];
var targetsource_array = targetSource.split(',');
for(i=0; i < targetcontrols_array.length; i++)
{
var control_name=targetcontrols_array[i];
var source=targetsource_array[i];
$.ajax({
url: action_url,
type: 'POST',
traditional: true,
async: false,
data: JSON.stringify( { allselected: allselected_flag, selectedIds: selectedvalues,targetControl:control_name, targetSource: source, dependency: dependencyOptions } ),
contentType: "application/json; charset=utf-8",
dataType: 'json',
success: function (response) {
//To clear existing items
var target= $("#"+response.targetControl);
target.multiselect('dataprovider', []);
var dropdown2OptionList = [];
for (i = 0; i < response.values.length; i++) {
dropdown2OptionList.push({
'label': response.values[i].text,
'value': response.values[i].value
})
}
console.log("--control"+control_name);
//re initialize the search plugin
target.multiselect('dataprovider', dropdown2OptionList);
target.multiselect('rebuild');
}
});
How can i ensure the first item in the loop also is getting filled with response values

You can try map to produce an array of Promise. After that use Promise.all() to execute this promises array.
var targetcontrols = [];
var targetcontrols_array = targetControl.split(',');
var targetsourcecontrols = [];
var targetsource_array = targetSource.split(',');
const arrOfPromises = targetcontrols_array.map(function(item, index) {
const control_name = item;
const source = targetsource_array[index];
return new Promise((resolve) => {
$.ajax({
url: action_url,
type: 'POST',
traditional: true,
async: false,
data: JSON.stringify( { allselected: allselected_flag, selectedIds: selectedvalues,targetControl:control_name, targetSource: source, dependency: dependencyOptions } ),
contentType: "application/json; charset=utf-8",
dataType: 'json',
success: function (response) {
//To clear existing items
var target= $("#"+response.targetControl);
target.multiselect('dataprovider', []);
var dropdown2OptionList = [];
for (i = 0; i < response.values.length; i++) {
dropdown2OptionList.push({
'label': response.values[i].text,
'value': response.values[i].value
})
}
console.log("--control"+control_name);
//re initialize the search plugin
target.multiselect('dataprovider', dropdown2OptionList);
target.multiselect('rebuild');
resolve(`done for url ${control_name}`) // Show log for checking process
}
})
})
Promise.all(arrOfPromises)

These 2 declarations:
var control_name = targetcontrols_array[i];
var source = targetsource_array[i];
maybe cause the problem. Because var has function scope and for loop is a block scope, so when you use the loop, these control_name and source variables got replaced from the next one, before used in ajax request. That's why you always get the last. You should change var into const or let which support block scope
const control_name = targetcontrols_array[i];
const source = targetsource_array[i];

First of all if you use jquery, utilize it's full potential, instead of for loops, use
$.each:
var targetcontrols = [];
var targetcontrols_array = targetControl.split(',');
var targetsourcecontrols = [];
var targetsource_array = targetSource.split(',');
$.each(targetcontrols_array, function(i, item)
{
var control_name=targetcontrols_array[i];
var source=targetsource_array[i];
$.ajax({
url: action_url,
type: 'POST',
traditional: true,
async: false,
data: JSON.stringify( { allselected: allselected_flag, selectedIds: selectedvalues,targetControl:control_name, targetSource: source, dependency: dependencyOptions } ),
contentType: "application/json; charset=utf-8",
dataType: 'json',
success: function (response) {
//To clear existing items
var target= $("#"+response.targetControl);
target.multiselect('dataprovider', []);
var dropdown2OptionList = [];
$.each(response.values, function(v, vItems) {
dropdown2OptionList.push({
'label': response.values[v].text,
'value': response.values[v].value
})
});
console.log("--control"+control_name);
//re initialize the search plugin
target.multiselect('dataprovider', dropdown2OptionList);
target.multiselect('rebuild');
}
});
});

Related

Split html table values using java script

I am working in rails application and From UI I need to select around 500 parameters(comma separated) in a table for execution. I am sending those selected data in AJAX call. I am unable to post huge string values hence I am planning to get the length of selected parameters if selected parameters count exceeds length 200. I need to split two or three batches and send for execution. How to implement this?
if (Device1) {
parameter_name = $('#parameters_object').val();
var getParams=parameter_name.split(',');
paramLen=getParams.length;
alert(paramLen);
if (paramLen > 200){
}
//m is a selected mac address length count
for (var i = 0; i < m; i++) {
(function () {
var macAdd = values[i];
$.ajax({
method: "POST",
url: "get_object",
dataType: "json",
data: {
parameter: getParams,
mac: macAdd,
protocol: protocol,
serialnumber: serialnumber,
},
success: function (result) {
console.log(result);
}
},
statusCode: {
404: function () {
console.log("Call failed");
}
}
});
})();
}
You can split your array into chunks of 200 items, and then loop over the chunk array and do your AJAX call.
const chunkSize = 200
const chunkParams = getParams.reduce((resultArray, item, index) => {
const chunkIndex = Math.floor(index/chunkSize)
if(!resultArray[chunkIndex]) {
resultArray[chunkIndex] = [] // start a new chunk
}
resultArray[chunkIndex].push(item)
return resultArray
}, [])
values.forEach(macAddress =>
chunkParams.forEach(chunkParam =>
$.ajax({
method: "POST",
url: "get_object",
dataType: "json",
data: {
parameter: chunkParam,
mac: macAddress,
....
},
...
});
)
)
You can directly do your AJAX call in the reduce loop, more performant but less readable.
You need to split params to batches and make ajax call for each batch. Try following:
if (Device1) {
parameter_name = $('#parameters_object').val();
var getParams=parameter_name.split(',');
paramLen=getParams.length;
alert(paramLen)
var paramsBatches = [];
var batchSize = 200;
for (i = 0, j = getParams.length; i < j; i += batchSize) {
paramsBatches.push(getParams.slice(i, i + batchSize));
}
//m is a selected mac address length count
for (var i = 0; i < m; i++) {
paramsBatches.forEach((batch, index) => {
var macAdd = values[i];
$.ajax({
method: "POST",
url: "get_object",
dataType: "json",
data: {
parameter: batch,
mac: macAdd,
protocol: protocol,
serialnumber: serialnumber,
},
success: function (result) {
console.log(result);
}
},
statusCode: {
404: function () {
console.log("Call failed");
}
}
});
}
}
}

JQuery TypeError: Converting circular structure to JSON in MVC

Facing error on JSON.stringify(ApplObj) :
How to post this object to controller
JQuery Code -
var ApplName = $("#ApplicantName").val();
var ApplMobile = $("#ApplicantMobile").val();
var ApplEmail = $("#ApplicantEmailId").val();
var ApplFHName = $("#ApplicantFHName").val();
var ApplObj = {
ApplicantName: ApplName, ApplicantMobile: ApplMobile, ApplicantEmailId: ApplEmail, ApplFHName: ApplicantFHName
}
$.ajax({
url: '#Url.Action("SaveApplicatDetail", "Dashboard")',
data: JSON.stringify(ApplObj),
dataType: 'json',
type: 'POST',
contentType: "application/json; charset=utf-8",
success: function (data) {
alert(data);
}
});
Controller Code...
this jsonresult used for save records and return value...
this code is working in other project....
public JsonResult SaveApplicatDetail()
{
try
{
var resolveRequest = HttpContext.Request;
TicketMasterModel TMM = new TicketMasterModel();
resolveRequest.InputStream.Seek(0, SeekOrigin.Begin);
string jsonString = new StreamReader(resolveRequest.InputStream).ReadToEnd();
if (jsonString != null)
{
TMM = (TicketMasterModel)js.Deserialize(jsonString, typeof(TicketMasterModel));
}
int TicketId = 0;
using (var db = new UnitOfWork())
{
DAL.tbl_TrnTicketMaster TM = new DAL.tbl_TrnTicketMaster();
TM.ApplicantName = TMM.ApplicantName;
TM.ApplicantMobile = TMM.ApplicantMobile;
TM.ApplicantEmailId = TMM.ApplicantEmailId;
TM.ApplicantFHName = TMM.ApplicantFHName;
TM.FK_CompanyId = 1;
TM.CustomerId = UserSession.UserId;
TM.IsSubmissionLocked = false;
TM.CreatedBy = UserSession.UserId;
db.tbl_TrnTicketMaster.Insert(TM);
TicketId = TM.PK_TicketId;
}
return Json(TicketId, JsonRequestBehavior.AllowGet);
}
catch (Exception)
{
throw;
}
}
basically JSON.stringify turns a Javascript object into JSON text and stores that JSON text in a string.
try this,
var ApplName = $("#ApplicantName").val();
var ApplMobile = $("#ApplicantMobile").val();
var ApplEmail = $("#ApplicantEmailId").val();
var ApplFHName = $("#ApplicantFHName").val();
var ApplObj = {
'ApplicantName': ApplName, 'ApplicantMobile': ApplMobile, 'ApplicantEmailId': ApplEmail, 'ApplFHName': ApplicantFHName
}
$.ajax({
url: '#Url.Action("SaveApplicatDetail", "Dashboard")',
data: JSON.stringify(ApplObj),
dataType: 'json',
type: 'POST',
contentType: "application/json; charset=utf-8",
success: function (data) {
alert(data);
}
});
Problem Resolved -
"JSON.stringify" is used array to convert it.
var ApplName = $("#ApplicantName").val();
var ApplMobile = $("#ApplicantMobile").val();
var ApplEmail = $("#ApplicantEmailId").val();
var ApplFHName = $("#ApplicantFHName").val();
var ApplDetails = {
ApplicantName: ApplName,
ApplicantMobile: ApplMobile,
ApplicantEmailId: ApplEmail,
ApplicantFHName: ApplFHName
}
var ApplObj = { ApplicantDetail: ApplDetails };
$.ajax({
url: '#Url.Action("SaveApplicatDetail", "Dashboard")',
data: JSON.stringify(ApplDetails),
dataType: 'json',
type: 'POST',
contentType: "application/json; charset=utf-8",
success: function (data) {
}
});

oo practice, make function not hard coding, return data after bind change

I want to find a way,give a dom as parameter and get data, from image_preview.
and separate image_preview.model() and image_preivew.on_chage() is event handler
make image_preview reusable not hardcode inside
I espect I will call image_preview pass dom in parameter, and return src as response , then I can use repsponse do something like append ...
var image_preview = {
on_change: function(wrap_dom, input_dom) {
$(wrap_dom).on('change', input_dom, function(event) { // I have to use on change because there are possible the `input dom` is new append...
var el_obj = $(this)[0];
var form_data = new FormData();
var file_length = el_obj.files.length;
for (var i = 0; i < file_length; i++) {
form_data.append("file[]", el_obj.files[i]);
}
image_preview.model(form_data).done(function(response) {
// console.log(response); // this is work
return response;
});
});
},
model: function(form_data) {
return $.ajax({
url: uri_public+'/admin/ajax/preview_file',
type: 'POST',
data: form_data,
processData: false,
contentType: false,
// async: false
});
}
}
var app_thumbnail = {
preview_controller: function() {
var wrap_dom = '.thumbnail';
var input_dom = '.upload-form input';
var result = image_preview.on_change(wrap_dom, input_dom);
// pass result to render view like append dom....
},
render: function() {
},
}
app_thumbnail.preview_controller();
Here is the easiest thing you can do:
var image_preview = {
on_change: function(wrap_dom, input_dom) {
$(wrap_dom).on('change', input_dom, function(event) {
var el_obj = $(this)[0];
var form_data = new FormData();
var file_length = el_obj.files.length;
for (var i = 0; i < file_length; i++) {
form_data.append("file[]", el_obj.files[i]);
}
image_preview.model(form_data).done(function(response) {
app_thumbnail.preview_controller(response);
});
});
},
model: function(form_data) {
return $.ajax({
url: uri_public+'/admin/ajax/preview_file',
type: 'POST',
data: form_data,
processData: false,
contentType: false,
// async: false
});
}
}
var app_thumbnail = {
preview_controller: function(response) {
var wrap_dom = '.thumbnail';
var input_dom = '.upload-form input';
var result = response;
}
}
// If you want to initialize it.
// image_preview.on_change(..., ...);

How to use q.js to chain backbone model?

I have the following:
var q = new app.models.OverwriteLineItemsProcess();
q.set('id', $("#process_id").val());
q.saveSource($("#source_quote").val());
q.lockSource();
saveSource is sending data to the backend using ajax. So is lockSource.
I want to execute in this SEQUENTIAL manner: saveSource >> lockSource.
How do I write the q.js to make it work?
By q.js, I mean https://github.com/kriskowal/q
UPDATE: added saveSource and lockSource
saveSource: function (quotation_id) {;
var type = "PUT";
var verb = "Updated";
var headers = {
'X-HTTP-Method-Override': type
};
var url = app.base_url + "/overwrite_line_items/" + this.id;
this.set('source_quote', quotation_id);
var data = this.toFormData();
var result = false;
var currentModel = this;
var settings = {
headers: headers,
type: type,
url: url,
data: data,
success: function(json) {
response = JSON && JSON.parse(json) || $.parseJSON(json);
console.log(response);
currentModel.lockSource();
$("#facebox-source-quote-status").html('<font color="green">SELECTED</font>');
},
error: function(response) {
$("#facebox-source-quote-status").html('<font color="red">UNABLE TO SELECT</font>');
},
dataType: 'json'
};
$.ajax(settings).done(function() {
});
},
lockSource: function () {
var type = "PUT";
var verb = "Updated";
var headers = {
'X-HTTP-Method-Override': type
};
var url = app.base_url + "/quotations/is_editable/" + this.attributes.source_quote;
var data = this.toFormData();
var result = false;
var currentModel = this;
var settings = {
headers: headers,
type: type,
url: url,
data: data,
success: function(response) {
console.log(response);
},
error: function(response) {
$("#facebox-source-quote-status").html('<font color="red">UNABLE TO SELECT</font>');
},
dataType: 'json'
};
$.ajax(settings).done(function() {
});
},
The jQuery.ajax function which you're using already returns a promise for its result. You just need to return that from your functions:
saveSource: function (quotation_id) {;
…
var settings = {
headers: headers,
type: type,
dataType: 'json', // jQuery will automatically parse it for you
url: url,
data: data
};
return $.ajax(settings).done(function() {
// ^^^^^^
$("#facebox-source-quote-status").html('<font color="green">SELECTED</font>');
// notice I did remove the currentModel.lockSource(); call from the callback
}, function() {
$("#facebox-source-quote-status").html('<font color="red">UNABLE TO SELECT</font>');
});
},
lockSource: function () {
…
var settings = // analoguous, no callbacks here
return $.ajax(settings).fail(function(response) {
$("#facebox-source-quote-status").html('<font color="red">UNABLE TO SELECT</font>');
});
}
Now you can easily chain them:
var q = new app.models.OverwriteLineItemsProcess();
q.set('id', $("#process_id").val());
q.saveSource($("#source_quote").val()).then(function(saveResponse) {
console.log(saveResponse);
return q.lockSource();
}).done(function(lockResponse) {
console.log(lockResponse);
});
You don't even need Q for that. If you want to use it, wrap the $.ajax() calls in a Q() invocation, as explained in the Converting JQuery Promises to Q section of the docs.

Jquery Ajax called 'click' called on an object that does not implement interface HTMLElement

I have the following javascript:
$('#edit_category').on('click','#btn_save_category_name',function(){
currently_edit.text($('#txt_edit_category').val());
edit_category_name(currently_edit,current_category_id);
$('#edit_category').modal('hide')
})
function edit_category_name(name, id){
$.ajax({
type: 'POST',
url: '/Category/edit_team_category',
dataType: 'json',
data: {
request: 'ajax',
name: name,
id: id
},
success: function (data) {
}
});
}
Now when i attempt this i get the following error: called 'click' called on an object that does not implement interface HTMLElement.
But if i comment the function line out aka : edit_category_name(currently_edit,current_category_id);
everything works fine.
Can anyone tell me why this is happening?
Update my full script
var mode = 'team';
var currently_edit = '';
var current_team_id = 0;
var current_category_id = 0;
jQuery(document).ready(function(){
//Main click function for Team (selection of team)
$('#team_wrapper').on('click', '.panel-heading', function () {
if(mode === 'team'){
current_team_id = $(this).siblings('small').text()
title = $(this).find('.text-white').text();
var i = 100;
$('#span_search').hide();
$('#btn_new_team').fadeOut();
$('.col-lg-3').each(function(){
$('.alt').toggle('slow');
$(this).fadeOut(300,function(){
$(this).remove();
});
});
$('#team_title').text('Select Category');
$('#btn_new_category').delay(500).fadeIn();
$('#selected_team_name').text(title);
$('#selected').delay(695).fadeIn();
$('#span_search').delay(500).fadeIn();
$('#back').delay(500).fadeIn();
generate_categories();
mode = 'category';
}else{
$(this).next('div').find('a')[0].click();
}
})
$('#team_wrapper').on('click', '.btn_administrate', function(){
current_team_id = $(this).next('.team_id').text();
load_team_members(current_team_id);
});
//Modal category:
//create
$('#btn_create_category').click(function(){
add_category($('#txt_create_category').val());
$('#group-form').modal('hide');
$('#txt_create_category').val('');
})
// edit
$('#team_wrapper').on('click','.team_category_edit',function(){
current_category_id= $(this).next('input').val()
edit_mode('txt_edit_category',$(this).closest("div").prev().find("h3"));
})
$('#edit_category').on('click','#btn_save_category_name',function(){
currently_edit.text($('#txt_edit_category').val());
edit_category_name(currently_edit,current_category_id);
$('#edit_category').modal('hide')
})
});
function edit_category_name(name, id){
$.ajax({
type: 'POST',
url: '/Category/edit_team_category',
dataType: 'json',
data: {
request: 'ajax',
name: name,
id: id
},
success: function (data) {
}
});
}
in this example:
var current_team_id = 1;
var current_category_id = 2;
What is the value of currently_edit? I am assuming this is a jQuery object not a text value. Try the following instead.
edit_category_name(currently_edit.text(),current_category_id);
Update
As Barmar mentioned, currently_edit.text(...) is invalid based on what you have shared. perhaps what you meant to do was:
currently_edit = $('#txt_edit_category').val();
Try changing this line currently_edit.text($('#txt_edit_category').val());
with this : currently_edit = $('#txt_edit_category').val();

Categories