Error array Ajax promises using "when" - javascript

I'm having an error when using several ajax calls, I put this in an array and I need capture when finish all.
My code is this:
var userId=[1,2,3];
var ajaxR = [];
for (var us in userId) {
var usId = userId[us];
ajaxR.push($.ajax({
type: "GET",
async: true,
contentType: "application/json; charset=utf-8",
dataType: "json",
url: "myurl",
data: { id: usId }
}));
}
$.when.apply($, ajaxR).always(function (e) {
//Here I have the error but arguments it's ok
var objects = arguments;
});
When I debbug this code I have an error in $.when function:
Uncaught TypeError: Cannot read property '0' of undefined
Update:
My complete function is it:
function UserFromWS(userId) {
var users = [];
var ajaxR = [];
for (var us in userId) {
var usId = userId[us];
ajaxR.push($.ajax({
type: "GET",
async: true,
contentType: "application/json; charset=utf-8",
dataType: "json",
url: "url",
data: { id: usId }
}));
}
$.when.apply($, ajaxR).always(function (e) {
var obj = arguments;
return obj;
});
// return users;
}
The error disapear if I put return users; in end of function. But it finish returning users array empty, before return obj. I need call the function in this way:
var allUsers = UserFromWS ([1,2,3]);
The function should return obj in $.when promise.

Fist thing to check is that "userId" is being passed as an array. Then the for loop need to be modified to correctly loop the array (Why is using "for...in" with array iteration a bad idea?).
Also the function needs to return a promise:
function UserFromWS(userId) {
var users = [];
var ajaxR = [];
for (var i = 0; i< userId.length; i++) {
var usId = userId[i];
ajaxR.push($.ajax({
type: "GET",
async: true,
contentType: "application/json; charset=utf-8",
dataType: "json",
url: "url",
data: { id: usId }
}));
}
return $.when.apply($, ajaxR).done(function (e) {
var obj = arguments;
return obj;
});
// return users;
}
Also you will need to wait for the result of this function:
var users = [10];
UserFromWS(users).then(function(result) { /* do stuff now */ });

Why do you save the ajax call to array, JQuery can recongnize the request by himself, and you can call the same $.ajax() many times without error.
Example:
$.ajax({
type: "GET",
async: true,
contentType: "application/json; charset=utf-8",
dataType: "json",
url: "url",
data: { id: usId }
}).done(function (e) {
var obj = arguments;
return obj;
});
Or if you want to continue with your system, know that when use promise
see https://api.jquery.com/jquery.when/

Related

How can a guarantee one ajax call is complete before calling another?

I am working on a flask application and there is this javascript function associated with a form
function applyQueries() {
// does some things
if(currentCatalog != ''){
addCatalogFilters(currentCatalog);
}
$.ajax({
type: 'POST',
url: "/applyQueries",
contentType: "application/json",
success:function(response){
// does some stuff here
})
}
The addCatalogFilters() function is also an ajax call. Both these calls change some variables in the python side of things. What I want to know is if the first ajax call (in addCatalogFilters), is guaranteed to execute and return before the second one. I am ending up with weird results that appear to be race conditions based on the order the ajax calls execute. Is this possible with code structured like this? Also if so, how can I fix it?
// Add user catalog filters
function addCatalogFilters() {
catalog = currentCatalog;
formData = new FormData(document.getElementById('catalogFilterForm'));
$.ajax({
type: 'POST',
url: "/addCatalogFilters",
data: formData,
processData: false,
contentType: false,
success: function (response){
document.getElementById(catalog + 'close').style.display = 'block';
document.getElementById(catalog + 'check').style.display = 'none';
addBtns = document.getElementsByClassName("addBtn");
removeBtns = document.getElementsByClassName("removeBtn");
for (i = 0; i < addBtns.length; i++) {
addBtns[i].style.display = "none";
removeBtns[i].style.display = "inline-block";
}
}
})
};
You can ensure with success function of ajax. First call a ajax (let's say ajax1) then call another ajax call within the success function of first ajax call (ajax1 success function).
addCatalogFilters(currentCatalog)
{
$.ajax({
type: 'POST',
url: "/the-post-usl",
success:function(response){
$.ajax({
type: 'POST',
url: "/applyQueries",
contentType: "application/json",
success:function(response){
// does some stuff here
});
})
}
function applyQueries() {
// does some things
if(currentCatalog != ''){
addCatalogFilters(currentCatalog);
}
}
It may not be the optimum way. But guarantee one ajax call is complete before calling another.
You could try using async/await like this:
async function applyQueries() {
if(currentCatalog !== ''){
const filtersAdded = await addCatalogFilters(currentCatalog);
}
// Perform AJAX call
}
By usinc async/await, your code will wait until the addCatalogFilters() function has resolved. However, for this to work, the addCatalogFilters() function should be async with a return value. Something like this:
async function addCatalogFilters(catalog){
// Ajax call
$.ajax({
type: 'POST',
url: "foo",
contentType: "application/json",
success:function(response){
return true
})
}
Depending on how applyQueries is called, you may need to have an await or .then where you call it. Note that you can also use "result = await addCatalogFilters(currentCatalog)" to put the ajax result into a variable result that you can work with and pass to your $.ajax call in applyQueries. I don't know the nature of your code, so I can't make any direct suggestions.
async function applyQueries() {
// does some things
if(currentCatalog != ''){
// await on the returned Promise-like jqXHR (wait for ajax request to finish)
// recommend assigning awaited result to a variable and passing to next $.ajax
await addCatalogFilters(currentCatalog);
}
return $.ajax({
type: 'POST',
url: "/applyQueries",
contentType: "application/json",
success:function(response){
// does some stuff here
})
}
// Add user catalog filters
function addCatalogFilters() {
catalog = currentCatalog;
formData = new FormData(document.getElementById('catalogFilterForm'));
// return the Promise-like jqXHR object: https://api.jquery.com/jQuery.ajax/#jqXHR
return $.ajax({
type: 'POST',
url: "/addCatalogFilters",
data: formData,
processData: false,
contentType: false,
success: function (response){
document.getElementById(catalog + 'close').style.display = 'block';
document.getElementById(catalog + 'check').style.display = 'none';
addBtns = document.getElementsByClassName("addBtn");
removeBtns = document.getElementsByClassName("removeBtn");
for (i = 0; i < addBtns.length; i++) {
addBtns[i].style.display = "none";
removeBtns[i].style.display = "inline-block";
}
}
})
};
You can use async/await. However, as no one has mentioned, I would like to demonstrate how you can accomplish this with Promise.
Lets define two functions:
function first_function(data) {
return new Promise((resolve, reject) => {
let dataSet = [[]];
let response;
$.ajax({
type: "POST",
url: 'example.com/xyz',
async: false,
data: data,
success: function (value) {
response = value;
dataSet = JSON.parse(response);
resolve(dataSet)
},
error: function (error) {
reject(error)
},
processData: false,
contentType: false
});
})
}
function second_function(data) {
return new Promise((resolve, reject) => {
let dataSet = [[]];
let response;
$.ajax({
type: "POST",
url: 'example.com/abc',
async: false,
data: data,
success: function (value) {
response = value;
dataSet = JSON.parse(response);
resolve(dataSet)
},
error: function (error) {
reject(error)
},
processData: false,
contentType: false
});
})
}
Now you can make sure that second_function() gets called only after the execution of ajax request in first_function() by following approach:
first_function(data)
.then(dataSet => {
//do other things
second_function(dataSet)
.then(dataSet2 => {
////do whatever you like with dataSet2
})
.catch(error => {
console.log(error);
});
});

AJAX GET returns undefined on the first call, but works on the second one

I am working on a real estate web app in ASP.NET MVC. My problem is in my Reservations section.
I am using AJAX to post in a Controller which returns a JSONResult. Here is my code:
Controller
[HttpPost]
public JsonResult SubmitReservation(ReservationViewModel rvm)
{
return Json(rvm, JsonRequestBehavior.AllowGet);
}
Main AJAX
var rvm = new ReservationViewModel();
getBuyerInfo(rvm.SelectedBuyerID, clientCallback);
getSiteInfo(rvm.SelectedSiteID, siteCallback);
getUnitInfo(rvm.SelectedUnitID, unitCallback);
$.ajax({
url: "/Reservations/SubmitReservation",
data: JSON.stringify(rvm),
type: "POST",
dataType: "json",
contentType: "application/json",
success: function () {
console.log(clientData);
console.log(siteData);
console.log(unitData);
//Assignment of data to different output fields
//Client Data
$('#clientName').html(clientData.FullName);
$('#clientAddress').html(clientData.Residence);
$('#clientContact').html(clientData.ContactNumber);
//Site Data
$('#devSite').html(siteData.SiteName);
$('#devLoc').html(siteData.Location);
////House Unit Data
$('#unitBlock').html(unitData.Block);
$('#unitLot').html(unitData.Lot);
$('#modelName').html(unitData.ModelName);
$('#modelType').html(unitData.TypeName);
$('#lotArea').html(unitData.LotArea);
$('#floorArea').html(unitData.FloorArea);
$('#unitBedrooms').html(unitData.NumberOfBedrooms);
$('#unitBathrooms').html(unitData.NumberOfBathrooms);
$('#unitPrice').html(unitData.Price);
$('#reservationDetails').show();
alert("Success!");
},
error: function (err) {
alert("Error: " + err);
}
});
Functions for fetching data
function getBuyerInfo(id, cb) {
$.ajax({
url: "/BuyersInformation/GetBuyerByID/" + id,
type: "GET",
contentType: "application/json",
dataType: "json",
success: cb
});
}
function getSiteInfo(id, cb) {
$.ajax({
url: "/Sites/GetSiteByID/" + id,
type: "GET",
contentType: "application/json",
dataType: "json",
success: cb
});
}
function getUnitInfo(id, cb) {
$.ajax({
url: "/HouseUnits/GetUnitByID/" + id,
type: "GET",
contentType: "application/json",
dataType: "json",
success: cb
});
}
function ReservationViewModel() {
var buyerId = $('#SelectedBuyerID').val();
var siteId = $('#SelectedSiteID').val();
var unitId = $('#SelectedUnitID').val();
var rsvDate = $('#ReservationDate').val();
var me = this;
me.ReservationDate = rsvDate;
me.SelectedBuyerID = buyerId;
me.SelectedSiteID = siteId;
me.SelectedUnitID = unitId;
}
function clientCallback(result) {
clientInfo = result;
clientData = clientInfo[0];
}
function siteCallback(result) {
siteInfo = result;
siteData = siteInfo[0];
}
function unitCallback(result) {
unitInfo = result;
unitData = unitInfo[0];
}
The whole code WORKS well for the second time. However, it does not work for the FIRST time. When I refresh the page and I hit Create, it returns undefined. But when I hit that button again without refreshing the page, it works well. Can somebody explain to me this one? Why does AJAX returns undefined at first but not at succeeding calls? Thanks in advance.
You are calling several ajax requests in your code, inside these functions:
getBuyerInfo(rvm.SelectedBuyerID, clientCallback);
getSiteInfo(rvm.SelectedSiteID, siteCallback);
getUnitInfo(rvm.SelectedUnitID, unitCallback);
and finally $.ajax({...}) after them, where you use results from pervious ajax calls.
Your problem is that the first ajax calls do not necessarily return results before your start the last ajax because they are all async. You have to make sure you get three responds before calling the last ajax. Use promises or jQuery when, like this:
var rvm = new ReservationViewModel();
$.when(
$.ajax({
url: "/BuyersInformation/GetBuyerByID/" + rvm.SelectedBuyerID,
type: "GET",
contentType: "application/json",
dataType: "json"
}),
$.ajax({
url: "/Sites/GetSiteByID/" + rvm.SelectedSiteID,
type: "GET",
contentType: "application/json",
dataType: "json"
}),
$.ajax({
url: "/HouseUnits/GetUnitByID/" + rvm.SelectedUnitID,
type: "GET",
contentType: "application/json",
dataType: "json"
})
).done(function ( clientResponse, siteResponse, unitResponse ) {
clientInfo = clientResponse;
clientData = clientInfo[0];
siteInfo = siteResponse;
siteData = siteInfo[0];
unitInfo = unitResponse;
unitData = unitInfo[0];
$.ajax({ ... }) // your last ajax call
});
AJAX calls are asynchronous. You last ajax call will not wait until your above 3 ajax calls finishes its work. so you can make use of $.when and .done here as below..
$.when(
getBuyerInfo(rvm.SelectedBuyerID, clientCallback);
getSiteInfo(rvm.SelectedSiteID, siteCallback);
getUnitInfo(rvm.SelectedUnitID, unitCallback);
).done(
$.ajax({
//Ajax part
})
);

How to load data in breaks from Ajax call?

Guys I have an ajax call on my page, which is being called on scroll down event (lazy loading).
This is the whole call :
function callMoreData()
{ $.ajax( {
type: "GET",
url: "/api/values/getnotice",
dataType: "json",
crossDomain: true,
async: true,
cache: false,
success: function (data) {
updateData(data);
},
error: function (x, e) {
alert('problem while fetching records!');
} });}
function updateData(data) {
updateData = function (data) { };
$.each(data, function (index, value) {
BindNotice(value);
});
}
function BindNotice(values)
{
...appending some div here with values...
}
now this call is returning all the data and display it all at once on first scroll event. What I want to do is, load the data in sets of two. For example, each loop gets executed on index 0 and 1 at first scroll, then on second scroll index 2 and 3 gets processed and then so on. How would I do about doing as? I have a very limited experience with JS/AJAX...
EDIT : CODE FROM CUSTOM LIBRARY :
$(".mainwrap .innnerwrap").mCustomScrollbar({
autoDraggerLength:true,
autoHideScrollbar:true,
scrollInertia:100,
advanced:{
updateOnBrowserResize: true,
updateOnContentResize: true,
autoScrollOnFocus: false
},
callbacks:{
whileScrolling:function(){WhileScrolling();},
onTotalScroll: function () {
callMoreData();
}
}
});
WebApi CODE :
[WebMethod]
[HttpGet]
public List<Notice> GetNotice()
{
string con = ConfigurationManager.ConnectionStrings["conn"].ConnectionString;
SqlConnection Connection = new SqlConnection(con);
string Query = "uSP_GetAllNotice";
SqlCommand cmd = new SqlCommand(Query, Connection);
cmd.CommandType = CommandType.StoredProcedure;
DataTable dt = new DataTable();
Connection.Open();
dt.Load(cmd.ExecuteReader());
Connection.Close();
List<Notice> objNoticeList = new List<Notice>();
foreach (DataRow row in dt.Rows)
{
Notice objNotice = new Notice();
objNotice.Subject = row["subject"].ToString();
objNotice.Date = Convert.ToDateTime(row["IssueDate"]);
objNotice.Department = row["Department"].ToString();
objNotice.Body = row["Body"].ToString();
objNotice.NoticeImage = row["NoticeImage"].ToString();
objNotice.Icon = row["Icon"].ToString();
objNoticeList.Add(objNotice);
}
return objNoticeList;
}
First of all, you have to make sure the server-side delivers only as mutch elements as you like, so that would be something like
[...]
type: "GET",
url: "/api/values/getnotice/" + start + '/' + amount,
dataType: "json",
[...]
start and amount have to be defined outside the function, in a higher scope, so it's available by the ajax function. While amount will be more or less constant, start can be calculated.
One option would be, to increment it on the success function.
Another solution can be, to count the divs you already appended to your DOM.
The result could be something like:
var amount = 2;
var start = 0;
function callMoreData(){
$.ajax( {
type: "GET",
url: "/api/values/getnotice/" + start + '/' + amount,
dataType: "json",
crossDomain: true,
async: true,
cache: false,
success: function (data) {
updateData(data);
start += amount;
},
error: function (x, e) {
alert('problem while fetching records!');
}
});
}
I recommend NOT to put it in the global namespace, but to put it in a own one.
Maybe you can use paging parameters to get your data in chunks of two items at a time. Let the server handle the work of figuring out how to break the response data into two items per page.
$.ajax({
type: "POST",
url: "/api/values/getnotice",
data: {
'PageSize': pageSize,
'Page': page
},
type: "GET",
dataType: "json",
crossDomain: true,
async: true,
cache: false,
success: function (data) {
updateData(data);
},
error: function (x, e) {
alert('problem while fetching records!');
}
});
Make a global variable such as
Var time_scrolled = 0; //in the beginning
when you receive scrolldown event your indexes at each request will be (time_scrolled*2) and (time_scrolled*2+1) then you increase time_scrolled by 1 as time_scrolled++;
Hope this will solve your problem.
Edited:
complete code
Var times_scrolled = 0; //in the beginning
Var global_data = [];
function callMoreData()
{ $.ajax( {
type: "GET",
url: "/api/values/getnotice",
dataType: "json",
crossDomain: true,
async: true,
cache: false,
success: function (data) {
global_data = data;
},
error: function (x, e) {
alert('problem while fetching records!');
} });}
callMoreData(); //fetch data at the time of loading since it won't miss at first scroll
function updateData(){
var initial = times_scrolled*2;
var final = initial+1;
for(var i=initial;i<data.length && i<=final;i++)
{
BindNotice(global_data[i]);
}
times_scrolled++;
}
function BindNotice(values)
{
...appending some div here with values...
}
// modify custom library code to:
$(".mainwrap .innnerwrap").mCustomScrollbar({
autoDraggerLength:true,
autoHideScrollbar:true,
scrollInertia:100,
advanced:{
updateOnBrowserResize: true,
updateOnContentResize: true,
autoScrollOnFocus: false
},
callbacks:{
whileScrolling:function(){WhileScrolling();},
onTotalScroll: function () {
updateData();
}
}
});
This is what I did to solve my problem. This is my ajax call
function callMoreData() {
var RoleCodes = $('#hiddenRoleCode').val();
$.ajax(
{
type: "GET",
url: "/api/alert/getalerts?RoleCode=" + RoleCodes + "&LastAlertDate=" + formattedDate,
dataType: "json",
crossDomain: true,
async: true,
cache: false,
success: function(data) {
$.each(data.data, function (index, value) {
update();
BindAlert(value);
});
},
error: function(x, e) {
alert('There seems to be some problem while fetching records!');
}
}
);
}

How can I make sure that other functions is run after this get function is fully completed and rendered?

I have this script that adds elements with data by a get json function.
$(document).ready(function() {
ADD.Listitem.get();
});
It basicly adds a bunch of html tags with data etc. The problem I have is following:
$(document).ready(function() {
ADD.Listitem.get();
var arr = [];
$(".Listitem-section-item-title").each(function() {
arr.push($(this.text()));
});
});
-
get: function(web) {
AST.Utils.JSON.get("/_vti_bin/AST/ListItem/ListitemService.svc/GetListItem", null, AST.Listitem.renderListitem);
},
renderListitem: function(data) {
$("#Listitem-template").tmpl(data["ListItemResults"]).prependTo(".ListItem-section-template");
}
and here is the json get:
ADD.Utils.JSON.get = function (url, data, onSuccess) {
$.ajax({
type: "GET",
contentType: "application/json; charset=utf-8",
async: true,
url: url,
data: data,
cache: false,
dataType: "json",
success: onSuccess,
error: ADD.Utils.JSON.error,
converters: { "text json": ADD.Utils.JSON.deserialize }
});
}
The array each loop is not running beacuse the get method is not finished with rendering the Listitem-section-item-title selector so it cant find the selector.
Is there any good solutions for this?
You could change your functions to return the promise given by $.ajax :
ADD.Utils.JSON.get = function (url, data) {
return $.ajax({
type: "GET",
contentType: "application/json; charset=utf-8",
async: true,
url: url,
data: data,
cache: false,
dataType: "json",
converters: { "text json": ADD.Utils.JSON.deserialize }
}).fail(ADD.Utils.JSON.error);
}
get: function(web) {
return AST.Utils.JSON.get("/_vti_bin/AST/ListItem/ListitemService.svc/GetListItem", null).done(AST.Listitem.renderListitem);
},
So that you can do
$(document).ready(function() {
ADD.Listitems.get().done(function(){
var arr = [];
$(".Listitem-section-item-title").each(function() {
arr.push($(this.text()));
});
});
});
Callback:
$(document).ready(function() {
ADD.Listitem.get(url,data,function(){
var arr = [];
$(".Listitem-section-item-title").each(function() {
arr.push($(this.text()));
});
});
});
Without callback:
If you cant get the get method to take a callback or return a promise then I think the best way will be to check when its done.
$(document).ready(function() {
ADD.Listitem.get();
var timer = setInterval(function(){
if ($("#thingWhichShouldExist").length>0){
var arr = [];
$(".Listitem-section-item-title").each(function() {
arr.push($(this.text()));
});
clearInterval(timer);
}
},50);
});
Retrieve the values and on success, call a function which will push the values into the array.
Also, arr.push($(this.text())); should be arr.push($(this).text());.

JSON.Parse causes error in javascript

I'm having some problems with JSON.Parse in my code and I cant find the reason of this I have a function which call two ajax functions, one on the start and another on the success function . Its working fine but when I'm try to parse the second one response the code breaks without giving any error and the real mystery is JSON.parse(object); dosent give any problem but when I use a variable to store the result like this var list =JSON.parse(object); my code broke and I dont what is the reason behind this my current code is given below
function getData()
{
$.ajax({
type: "POST",
url: "MyPage.aspx/GetData",
data: JSON.stringify({ data: data})
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response) {
var result = JSON.parse(response.d);
var temp = 0;
for (var i = 0; i < result.length; i++) {
if (result[i].data > 1) {
var subList = JSON.parsegetFullData (result[i].id));
}
}
});
}
function getFullData (id) {
var sublist;
$.ajax({
type: "POST",
url: "MyPage.aspx/GetData2",
data: JSON.stringify({ id: id }),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response) {
return response.d;
}
});
}
any thought will help a lot
When you use $.ajax with dataType:"json", the response is already parsed for you. And there doesn't seem to be a reason to try to parse response.d.
Simply use
$.ajax({
type: "POST",
url: "MyPage.aspx/GetData",
data: JSON.stringify({ data: data})
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (results) {
for (var i = 0; i < results.length; i++) {
console.log(results[i].id, results[i].LastName);

Categories

Resources