Push item into new array within Ajax method - javascript

I have the following array
var arrayOfResults = []; // Results after like statement
I make a call to the database which returns me a json result as shown here:
[{
"id": "{fcb42c9c-3617-4048-b2a0-2600775a4c34}",
"pid": "{34214CCB-90C3-4D75-958B-5A1D0FBDD971}",
"ttl": "Easter Bunny",
"img": "/~/media/Images/Recipes/Easter/Filled Pasta/LF_Baked-Spring-Vegetables-Ravioli_920.ashx?h=910\u0026w=910",
"url": "Some url",
"taggedwith": ["{3A54907D-4171-4F4E-8FE8-3A38DA1E874F}", "{6CD78C6B-F435-45EC-BE16-810E80311C23}", "{74528A6F-C40B-4030-A278-A4C9A2F46A47}", "{6DC82B78-61F6-45A0-A63C-EA590BB1057E}", "{E9EF1A41-51D0-403D-9373-37B7A880B251}"],
"articleddate": "2015-05-02",
"tname": "Recipe",
"rbrand": ["{1F6EDA5D-4681-40F0-B455-7C343AC25B72}"]
}, {
"id": "{2e4b04b6-334f-42e9-afd7-ddc4e08417ad}",
"pid": "{C611BAC8-E8E0-4693-920B-93BD5EE2386B}",
"ttl": "Latina Fettuccini \u0026 Summer Sauce with Prawns Recipe",
"img": "/~/media/Images/Recipes/Latina Fresh/Plain Pasta/LF_Fettuccini-Summer-Sauce-Prawns_920.ashx?h=910\u0026w=910",
"url": "Some url",
"taggedwith": ["{3A54907D-4171-4F4E-8FE8-3A38DA1E874F}", "{6CD78C6B-F435-45EC-BE16-810E80311C23}", "{74528A6F-C40B-4030-A278-A4C9A2F46A47}", "{6DC82B78-61F6-45A0-A63C-EA590BB1057E}", "{E9EF1A41-51D0-403D-9373-37B7A880B251}"],
"articleddate": "2015-05-02",
"tname": "Recipe",
"rbrand": ["{1F6EDA5D-4681-40F0-B455-7C343AC25B72}"]
}]
On the UI I have a text field, which the user can enter free text.
I call the following ajax method when the user has entered roughly 5 characters, what I'm trying to achieve is I want to perform a like statement on the ttl field within the above array, If the ttl field matches or is like the freeText the user has entered then I want to push that item in to the array 'arrayOfResuts' however I see the alert message found yet it doesn't push the item into the new array, I know this because I alert the length at the end of the ajax call and its 0;
var addItem = false;
var freeText = $('#searchKeywords').val();
$.ajax({
url: 'search?t=&s=DateDesc&type=globalsearch&q=',
type: 'GET',
dataType: 'json',
success: function (searchDataList) {
console.log(searchDataList)
for (var i = 0; i < searchDataList.length; i++) {
addItem = false;
if (freeText.length > 0) { // Filter on free text
if (searchDataList[i].ttl.indexOf(freeText) > -1) { // if title contains free text then we need to add it to the arrayOfResults[].
alert('found');
arrayOfResults.push(searchDataList[i]) // This doesn't seem to work.
addItem = true;
}
}
} // End of for loop
},
error: function (request, error) {
}
});
alert(arrayOfResults.length);
Now I'm not 100% sure what's actually going wrong, so any help would be appreciated.

Your alert is running before your AJAX request is complete.
Since the AJAX request is asyncronous the console.log() code runs before the success is called and so your not printing the result you want.
To print the results simply print within the success and error functions of the AJAX request. Doing so in the complete function will not help since it runs asyncronously from the others.

As the other answers mentioned you need to handle the data within the success block. You can do it directly like below, or for more complex cases call a new function to handle the data at the end of the success statement.
Update code:
var freeText = $('#searchKeywords').val();
$.ajax({
url: 'search?t=&s=DateDesc&type=globalsearch&q=',
type: 'GET',
dataType: 'json',
success: function (searchDataList) {
console.log(searchDataList);
for (var i = 0; i < searchDataList.length; i++) {
addItem = false;
if (freeText.length > 0) {
if (searchDataList[i].ttl.indexOf(freeText) > -1) {
alert('found');
arrayOfResults.push(searchDataList[i]);
addItem = true;
}
}
} // End of for loop
if (arrayOfResults.length > 1) {
alert(arrayOfResults.length);
console.log(arrayOfResults);
}
},
error: function (request, error) {
}
});

Your alert will always be 0 because AJAX is asynchronous (the A in AJAX stands for that) and you call your alert synchronously.
What happens is, the ajax request gets the data while the synchron code runs as usual. Now that the ajax request is done clearly after you call your alert it cannot log anything that makes sense.
If you want a function to be called when the asynchronous request is done, wheter it was successful or not, use done: additionally to success: and error:. This code will run when the request is done and show you the actual length.

Related

Wait for $.ajax result inside .each function

I have function that search for every element with a specific class:
$("#stepSurveyCtnId .questionCtnClass").each(function () {}
Inside each step, I check if a question is of type customer:
var type = $(this).children().data("question-type");
var isCustomerQuestion = false;
switch (type) {
case "Name":
case "Email":
isCustomerQuestion = true;
break;
}
If it's customer type, I get the next id of the customer's table from the database:
if(isCustomerQuestion) {
if (customerId == -1) {
$.ajax({
method: "POST",
url: urlCustomerCreate,
success: function (ajaxData) {
customerId = ajaxData.NumericValue;
}
});
}
}
The issue is that in the second iteration of the .each() function, customerId is still = -1, when it should be 1305 for example.
It seems that the execution don't stop in the $.ajax call, or the iterations are executed at the same time and the second iteration don't receive the customerId from the first iteration.
I'm still not 100% clear on sure on how everything is structured for you, but here is one way of handling asynchronicity in JavaScript (adapted from #ShubHam's answer)
function handleQuestion(questionElements, index, customerId) {
if (questionIndex >= questionElements.length) return;
var type = $(this).children().data("question-type");
var isCustomerQuestion = false;
switch (type) {
case "Name":
case "Email":
isCustomerQuestion = true;
break;
}
if(isCustomerQuestion) {
if (customerId == -1) {
$.ajax({
method: "POST",
url: urlCustomerCreate,
success: function (ajaxData) {
handleQuestion(questionElements, questionIndex + 1, ajaxData.NumericValue);
}
});
} else {
// Have ID now
handleQuestion(questionElements, questionIndex + 1, customerId);
}
}
}
// Go
handleQuestion($("#stepSurveyCtnId .questionCtnClass"), 0, -1);
This will only continue to the next iteration after the success callback has been triggered.
Put logic inside one function (say function 1) and ajax call inside other function.
Call ajax function from function 1. Inside success call function 1 with required params
Update (example added):
var x=['a','b','c']
var elm=document.getElementById('demo')
x.forEach(function(temp){
elm.innerHTML=elm.innerHTML+temp
})
<div id='demo'></div>
This can be converted to new logic as
var x=['a','b','c']
function sethtml(temp,length,maxlength){
//here ajax call can be placed
var elm=document.getElementById('demo')
elm.innerHTML=elm.innerHTML+temp
//inside success function of ajax
traverse(length+1,maxlength)
}
function traverse(length,maxlength){
if(length>=maxlength)
{
//all calls done next steps to perform
}else{
sethtml(x[length],length,maxlength)
}
}
traverse(0,x.length)
<div id='demo'></div>
Advice to be considered from Jamie-Day in comments: Check your logic for scope of improvement. Accessing db results in for each kind of scenario generally can be avoided(ideally it should be avoided for better user experience)
Change your ajax code. add "async: false" so that each code next to ajax will wait for ajax result
if(isCustomerQuestion) {
if (customerId == -1) {
$.ajax({
method: "POST",
async: false,
url: urlCustomerCreate,
success: function (ajaxData) {
customerId = ajaxData.NumericValue;
}
});
}
}
First, you need to think asynchronously.
Code that need to run after the ajax should be called from the success function. You also want to add error function to handle server errors.
Second, to improve speed and bandwidth I'd reduce number of AJAX calls to a single one, by joining all IDs together in a single AJAX request.
It require server-side changes and you did not provide the server-side, so I'll leave server side to you.
// Prepare ajax call
var customerData = [];
var customerCreateData = [];
$("#stepSurveyCtnId .questionCtnClass").each(function () {
var type = $(this).children().data("question-type");
var isCustomerQuestion = false;
switch (type) {
case "Name":
case "Email":
isCustomerQuestion = true;
break;
}
// Set customerId and customerCreateData
if(isCustomerQuestion) {
if (customerId == -1) {
customerCreateData.push(customerCreateData);
}
}
}); // end each
if (customerCreateData.length) {
$.ajax({
method: "POST",
url: urlCustomerCreate,
data: customerCreateData,
success: function (ajaxData) {
customerData = ajaxData.customerData;
doAmazingThingsWithCustomers(customerData);
},
error: function(jqXHR, textStatus, errorThrown) {
alert('Server error: ' + errorThrown);
}
});
}
The first A in AJAX stands for Asynchronous which means that the ajax calls would get executed and would not wait for the call to finish. This way we can let users interact with other elements on the page and provide a good user experience.
If we make the AJAX calls asynchronous by setting the async option to false, then the browser would wait for the ajax call to complete and users would not be able to interact with the elements until the call has completed. With the increase in number of calls, this blockage time would increase.
I would suggest you find a better alternative than this.

How to ensure that a function containing multiple $.ajax calls runs fully synchronously and also allows for browser repaints as it executes

I've been working on getting a function written to:
1) Process an input array using $.ajax calls to fill an output array (below this is inputList)
2) Below is what I have, but I'm having issues with it:
requestData(), when I call it, runs straight through to processing the outputList array without having fully populated/filled it - it puts one value into it then starts to process that, but the function still apparently runs on seperately to the subsequent processing asynchronously. I need it to be fully synchronous so that it does not return until the inputList array has been fully processed.
I'm not seeing the browser repainting the div that has its html updated on every call of the runajax() function - I'm attempting to do this with a setTimeout.
3) I've set the ajax request to be synchronous (async : false) - but this doesn't seem to help
I've tried to use jQuery's $.when to provide an ability to ensure that everything gets called in sequence - but clearly I'm not doing this correctly.
Would appreciate any help - I've asked previous related questions around this and had some useful help - but I've still not resolved this!
Thanks
//declare holding function requestData - expects a non-empty input data array named inputList
function requestData() {
//declare inner function runajax
function runajax() {
if(inputList.length > 0) {
//get first item from inputlist and shorten inputList
var data = $.trim(inputList.shift());
function getData() {
//send the data to server
return $.ajax({
url: 'sada_ajax_fetch_data.php',
cache: false,
async: false,
method: "post",
timeout: 2000,
data: {
requesttype: "getmydata",
email: encodeURIComponent(data)
}
});
}
function handleReturnedData (response) {
response = $.trim(decodeURIComponent(response));
//update the div inner html
if(response == "Failed") {
$('#fetchupdatestatus').html('There was an error retrieving the data you requested!');
} else {
$('#fetchupdatestatus').html('The item returned was '+response);
}
//add the response from ajax to the end of the outputList array
outputList.push(response);
//set up the next ajax call
var doNextBitOfWork = function () {
runajax();
};
//call setTimeout so that browser shows refreshed div html
setTimeout(doNextBitOfWork, 0);
//return
return $.when();
}
//do the next ajax request and response processing
return getData().done(handleReturnedData);
} else {
//did the last one so return
return $.when();
}
}
//kick off the ajax calls
runajax();
}
var inputList = new Array();
var outputList = new Array();
.....load +/- 100 values to be processed using ajax into array inputList
requestData();
.....process stuff in array outputList
.....etc
There was my answer with "you're doing it wrong" earlier, but then I just decided to show, how you can do it (almost) right: https://jsfiddle.net/h4ffz1by/
var request_maker = {
working: false,
queue: [],
output: [],
requestData: function(inputList) {
if (request_maker.working == true) {
return false;
}
request_maker.output = [];
request_maker.working = true;
while (inputList.length > 0) {
var data = $.trim(inputList.shift());
request_maker.queue.push(data);
}
console.log(request_maker.queue);
request_maker.doTheJob();
return true;
},
doTheJob: function() {
current_data_to_send = request_maker.queue.shift();
console.log(current_data_to_send);
if (typeof current_data_to_send != 'undefined' && request_maker.queue.length >= 0) {
$.ajax({
url: '/echo/json/',
cache: false,
method: "post",
timeout: 2000,
data: {
requesttype: "getmydata",
email: encodeURIComponent(current_data_to_send)
},
success: function(data, status, xhrobject) {
console.log(xhrobject);
request_maker.handleReturnedData(data);
},
});
} else {
request_maker.working = false;
console.log('all data has been sent');
}
},
handleReturnedData: function(response) {
console.log(response);
response = $.trim(decodeURIComponent(response));
//response= 'Failed';//uncomment to emulate this kind of response
if (response == "Failed") {
$('#fetchupdatestatus').append('There was an error retrieving the data you requested!<br/>');
} else {
$('#fetchupdatestatus').append('The item returned was ' + response + '<br/>');
request_maker.output.push(response);
}
request_maker.doTheJob();
if (request_maker.working == false) {
console.log('all requests have been completed');
console.log(request_maker.output);
}
}
}
inputList = [1, 2, 3, 4, 5, 6];
if (request_maker.requestData(inputList)) {
console.log('started working');
}
if (!request_maker.requestData(inputList)) {
console.log('work in progress, try again later');
}
Note that I've changed request path to jsfiddle's ajax simulation link and replaced html() with append() calls to print text in div. The calls are made and get handled in the same order as it is in inputList, still they don't lock user's browser. request_maker.output's elements order is also the same as in inputList.
Have in mind, that you will need to add error handling too (probably just a function that pushes 'error' string into output instead of result), otherwise any ajax error (403/404/502, etc.) will get it "stuck" in working state. Or you can use complete instead of success and check request status right there.
UPD: Answer to the question: you cannot get both. You either use callbacks and let browser repaint inbetween asynchroneous requests or you make requests synchroneous and block browser untill your code finished working.
UPD2: There actually is some information on forcing redraw, however I don't know if it will work for you: Force DOM redraw/refresh on Chrome/Mac

For loop is not working properly in Javascript function

I am sending Ajax request to php page using Javascript.
My main goals is to send ajax request to PHP page and get the response which I have done that already.
The problem is when the Ajax send back the response the Javascript cannot send this to HTML properly.
Look at my code so you can understand clearly.
Javascript code:
function get_rental_fee(){
var count_model = $('#count_model').val();
for(var i =0; i < count_model; i++){
var hours = $('#hours').val();
var modelid = $('#modelid_multi'+i).val();
var get_tax = $('#get_tax_multi'+i).val();
var get_counter = $('#get_counter_multi'+i).val();
var myData = "hours="+hours+"&modelid="+modelid+"&get_tax="+get_tax;
jQuery.ajax({
type: "POST", // Post / Get method
url: "get_rental_fee.php", //Where form data is sent on submission
dataType:"text", // Data type, HTML, json etc.
data:myData, //Form variables
success:function(response){
var result = response.split('|');
document.getElementById('rental_price_multi'+i).value=result[0];
document.getElementById('tax_multi'+i).value=result[1];
},
error:function (xhr, ajaxOptions, thrownError){
//On error, we alert user
alert(thrownError);
}
});
}
}
The problem is here:
document.getElementById('rental_price_multi'+i).value=result[0];
document.getElementById('tax_multi'+i).value=result[1];
The loop runs 3 times and Php is sending me back the response 3 times. But in Javascript Theses 2 lines are only showing VALUES of 3rd Times not 1st and 2nd.
But I am receiving response of all 3 times.
Also when I run the code the javascript returns back an error:
Uncaught Type Error: Cannot set Property 'value' of null
Please help me where I am doing wrong
Problem is $.ajax is by default async: true, so the value of i in loop is not the desired value when it reaches success.
You can simply make the ajax sync:
$.ajax({
async: false,
...
})
Edited:
If you still want to it to be async, you need to use closures.
for(var i =0; i < count_model; i++){
(function(i){// closure `i`
$.ajax({
type: "POST",
...
});
})(i);//<-- for loop `i`
}
Your problem is that i inside the callback no longer has the value it did when you registered the callback. This is a very common problem.
A common solution is to "close over" the variable i so that it retains the correct value:
success: (function(i) {
return function(response) {
var result = response.split('|');
document.getElementById('rental_price_multi'+i).value=result[0];
document.getElementById('tax_multi'+i).value=result[1];
})(i)
The outer function is passed i as a parameter, at which point its value in the inner callback function becomes fixed.

In Javascript, process list synchronously

I have a given collection of items to be processed; each item must wait for the completion of the previous one.
By collection of items I mean an array of integer values.
By "processing" I mean make a POST to a HTTP server, passing the integer value of each array element.
I've found something that looks like waht I'm looking for: doSynchronousLoop.js but I wonder if there are alternatives.
If your site may pause rendering while doing the requests, here's a solution with jQuery:
// process 5 items
for (var i = 0; i< 5; i++) {
// ajax request done with jquery
$.ajax({
async: false, /* this makes it execute synchronously */
url: "the url to handle item #i",
type: "POST",
success: function(msg) {
// process data for item #i
}
})
}
Edit: you can solve it asynchronously, too:
items = [put your items here]
current_item = 0
function processItem() {
if (current_item == items.length) {
// list processing finished
return;
}
$.ajax({
async: true,
url: "the url to handle item #current_item",
type: "POST",
success: function(msg) {
// process data for item #current_item
processItem();
current_item++;
}
})
}
Don't miss to put the variables in a scope, I just left them in global scope to make the example easier to understand.
See also the docs: jQuery.ajax

my function can't pass it's parameter value javascript

Ive been struggling to pass my parameters from a functions but I just really can't figure out where did I go wrong. I have a function that have a parameters that I want to pass to my postData to display datas in my jQgrid. Here's my function code with parameters:
function getTID(hdrID){
var selected = $('#editTallyHdr').val();
var hdrID = '';
var hdrNo = '';
var nameFlag=0;
var par_ams = {
"SessionID": $.cookie("SessionID"),
"dataType": "data"
};
$.ajax({
type: 'GET',
url: 'processjson.php?' + $.param({path:'getData/tallyHdr',json:JSON.stringify(par_ams)}),
dataType: primeSettings.ajaxDataType,
success: function(data) {
if ('error' in data)
{
showMessage('ERROR: ' + data["error"]["msg"]);
}
else{
$.each(data['result']['main']['rowdata'], function(rowIndex, rowDataValue) {
$.each(rowDataValue, function(columnIndex, rowArrayValue) {
var fldName = data['result']['main']['metadata']['fields'][columnIndex].name;
if (fldName == 'transaction_id'){
hdrID = rowArrayValue;
}
if (fldName == 'transaction_num'){
hdrNo = rowArrayValue;
if(selected == hdrNo){
nameFlag =1;
};
}
});
});
}
}
});
return (hdrID);
}
and here is my jQgrid code where I call that function to get it's parameter:
$("#tblPlank").jqGrid({
url: '',
datatype: 'local',
jsonReader : {
.
.
.
serializeGridData: function(postData) {
var ctr =0;
var filt=[];
var c=[];
var jsonParams = {
'SessionID': $.cookie("SessionID"),
'dataType': 'data',
'transaction_id':getTID(hdrID),
'filters': c,
'lines':plank_data,
'recordLimit': postData.rows,
'recordOffset': postData.rows * (postData.page - 1),
'rowDataAsObjects': false,
'queryRowCount': true,
'sort_fields': postData.sidx
};
.
.// some code here
.
.
return 'json=' + JSON.stringify(jsonParams);
},
loadError: function(xhr, msg, e) {
showMessage('HTTP error: ' + JSON.stringify(msg) + '.');
},
colNames:[...],
colModel:[
........................
],
.
.
.
caption: "Tally Transaction Details/Lines"
I also have another code where I want to get that parameter. Here's the last code:
var par_ams = {
"SessionID": $.cookie("SessionID"),
"dataType": "data",
"transaction_id": getTID(hdrTID)
}
$('#tblPlank').setGridParam({
url:'processjson.php?path=' + encodeURI('getData/tallyLnDtl') + '&json=' + encodeURI(JSON.stringify(par_ams)),
datatype: primeSettings.ajaxDataType,
});
$('#tblPlank').trigger('reloadGrid');
Those codes below that function getTID(hdrID) cant retrieve the parameter, it shows empty. This maybe simple to anyone, but I really need help on this.. been working with this for quite long hours.
This is a very common misunderstanding. I've probably answered 15 of these questions in the last two weeks alone. An ajax call is an asynchronous call. That means that when you make the ajax call, it just STARTs the request. Then, while that request goes in the background, your code immediately keeps executing. That means that your function getTID() returns before the ajax call has even completed and it's value is not yet known. Thus, there is no way to return the response value from the ajax function when you return from getTID() as it is simply not known yet.
To work with asynchronous function calls (like ajax calls), you have to change your programming style to something that works asynchronously. In this case, the response to your ajax call is ONLY known in the success handler for the ajax all. So, you have to restructure your code to continue on with the execution of your processing and the handling of the ajax response from the success handler. If you have only a little bit of work to do, then you can put it all in the success handler. If you have a lot of work to do, then you can put all the rest of that work in a function call and call it from the success handler.
The problem is that you're doing an ajax-request (asynchronous request). Then the function does not wait for an answer to arrive, but just continues and returns hdrID (which isn't set at the time). After that a response comes in, and the success-method is called, which sets hdrID to the appropiate value.
The common way to solve this is to execute a specific function with the desired values when the success-method is executed. It's too much code to look into, but it could go something like this:
function fetchContent(continueFunction) {
$.ajax(params).success(function(reply) {
// retrieve desired params from reply
continueFunction(retrievedParameters);
}
}
What you could do is define getTID to take in a callback to execute once it has the id, for instance
function getTID(hdrID, callback) {
//ajax stuff....
success: function (data) {
// Error checks, etc
hdrID = //something dependent on data
callback(hdrID); // THIS IS THE IMPORTANT PART
}
the callback will execute after the request has returned, when it is safe to use the data returned from the ajax request that will be needed in the callback. You could wrap all of the code that needs the return value of the request in the callback, for example
getTID(hdrID, function (ID) {
var params = {
"SessionID": $.cookie("SessionID"),
"dataType": "data",
"transaction_id": ID //USE ID
}
$('#tblPlank').setGridParam({
url:'processjson.php?path=' + encodeURI('getData/tallyLnDtl') + '&json=' + encodeURI(JSON.stringify(par_ams)),
datatype: primeSettings.ajaxDataType,
});
$('#tblPlank').trigger('reloadGrid');
};
});

Categories