Having a hard time showing results after an AJAX call - javascript

Browser: IE 11
PlatForm: SharePoint 2016
I am trying to cache data into an array when page loads, so that the array can be used throughout the rest of my code for efficiency purposes. I have 4 arrays and the data to populate the arrays will be coming form 4 different SharePoint lists. I am using jQuery to make the calls to the lists and to retrieve the data. I believe that the way I have done it is wrong because though the calls are successfully made the arrays are not populated by the time I use them. Here's an excerpt of the code:
var cacheNavData = [];
var cacheSubNavData = [];
var cacheMegaMenuData = [];
var cacheCategoryMenuData = [];
$(document).ready(function(){
getNavData();
getSubNavData();
getMegaMenuData();
getCategoryMenuData();
})
function getNavData(){
var endPointUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbyTitle('"+lName+"')/items";
var headers = {
"accept":"application/json;odata=verbose"
}
$.ajax({
url:endPointUrl,
async:false,
type:"GET",
headers: headers,
success: function success(data) {
cacheNavData = data.d.results;
}
});
}
function getSubNavData(){
var endPointUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbyTitle('"+lName+"')/items?$select=parentNav/URL, parentNav/URLNAME,subLink&$expand=parentNav";
var headers = {
"accept":"application/json;odata=verbose"
}
$.ajax({
url:endPointUrl,
async:false,
type:"GET",
headers: headers,
success: function success(data) {
cacheSubNavData = data.d.results;
}
});
}
function getMegaMenuData(){
var endPointUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbyTitle('"+lName+"')/items";
var headers = {
"accept":"application/json;odata=verbose"
}
$.ajax({
url:endPointUrl,
async:false,
type:"GET",
headers: headers,
success: function success(data) {
cacheMegaMenuData = data.d.results;
}
});
}
function getCategoryMenuData(){
var endPointUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbyTitle('"+lName+"')/items";
var endPointUrl = "_api/web/lists/getbyTitle('"+lName+"')/items";
var headers = {
"accept":"application/json;odata=verbose"
}
$.ajax({
url:endPointUrl,
async:false,
type:"GET",
headers: headers,
success: function success(data) {
cacheCategoryMenuData = data.d.results;
}
});
}
console.log(cacheNavData);
console.log(cacheSubNavData);
console.log(cacheMegaMenuData);
console.log(cacheCategoryMenuData);
Now, I know that the problem is Asynchronous and I'm still trying to wrap my head around it. I've looked at several problems and explanations on this site. I've also looked at different articles and watched videos but I still don't fully get it. In this situation, I know that when I'm looking to check the data in the console.log(), the Ajax call has not returned the data yet. Through all of my readings, I have come to understand that. The part that I'm not getting is the fix or the how do I prevent that from happening. I tried the following to fix this problem but it didn't work. Maybe I did something wrong. Any help would be much appreciated. Thanks!
var cacheNavData = [];
var cacheSubNavData = [];
var cacheMegaMenuData = [];
var cacheCategoryMenuData = [];
$(document).ready(function() {
var cache1 = getData("Navigation", "cacheNavDataVar");
var cache2 = getData("Sub Navigation", "cacheSubNavDataVar");
var cache3 = getData("category menu", "cacheCategoryMenuDataVar");
var cache4 = getData("Mega Menu Category", "cacheMegaMenuDataVar");
$.when(cache1, cache2, cache3, cache4).done(function(results){
if(results){
createNavigation(cacheNavData)
}
})
});

I hope above highlighted line is self explanatory. If you call multiple ajax async : true requests then browser opens new tcp port for every request and as soon it get response from any request, it starts calling ajax success function.

Related

May i know why is my ajax called two time? or is actually normal?

I am new to js.
I am trying to call the API and save the data in a variable (obj = [])
But i go thru the console, my ajax call called two times. May i know why?
This is the console on my browser that i found out it is called two time:
Below is my code:
$(function (){
var obj = [];
var selected = $("select.dr-down option:selected").click().val();
var markup = '';
getAPI();
console.log('obj = ', obj);
function getAPI() {
$.ajax({
url: 'http://www.mocky.io/v2/5d73bf3d3300003733081869',
method: 'GET',
}).done(function (data) {
data.forEach(function (data) {
obj.push(data);
});
})
}
})

jquery.html array as a selector

Below is my code for getting a data from api for 2 different URLs. The result is positive when I use $('#resultDiv1').html instead of opts[j].html. On using opts[j].html, I am getting error as opts[j].html is not a function'. Where is the mistake? Please help me.
var domain = "https://example.com/api#token=";
var detail = "/some_data"
$(document).ready(function() {
var token = ['260105', '49409' ];
var resultElement1 = $('#resultDiv1');
var resultElement2 = $('#resultDiv2');
var opts = ["resultElement1", "resultElement2"];
for (j=0; j<1; j++){
$.ajax({
url: domain + token[j] + detail,
method: 'get',
dataType: 'json',
success: function(response) {
opts[j].html(response.data.candles[response.data.candles.length - 1][4]);
}
})
}
});
That won't work because "resultElement1" and "resultElement2" are two different strings in the opts array. To use the selected elements, you need to create array using the variables resultElement1 and resultElement2, like this:
var opts = [resultElement1, resultElement2];
Also, your for loop will only work for resultElement1, because you end the iteration as soon as j becomes 1.

AJAX callback to retrieve layers name from GeoServer fails with an assertion error

I'm writing something to get all the layers names from my GeoServer. This is my code:
function getData() {
return $.ajax({
url: "http://localhost:8080/geoserver/ows?service=wms&version=1.1.0&request=GetCapabilities",
type: 'GET'
});
}
function onComplete(data) {
var parser = new ol.format.WMSCapabilities();
var result = parser.read(data.responseText);
var layersArray = result.Capability.Layer.Layer;
layersNameArray = [];
for(i=0;i<layersArray.length;i++){
layersNameArray.push(layersArray[i].Name)
}
return layersNameArray
}
getData().done(onComplete)
I'm far from an expert with asynchronous calls, but I think this one is supposed to work. If I stock the getData() result in a variable and run the onComplete() function line by line, the code works. But when I run the code with getData().done(onComplete), it always fails at the var result = parser.read(data.responseText);line with Assertion error: Failure.
Any idea why this isn't working ?
Edit:
This code works, but nothing is returned. I want the function to output the layersNameArrayvariable. How should I proceed ?
function getData() {
$.ajax({
url: "http://localhost:8080/geoserver/ows?service=wms&version=1.1.0&request=GetCapabilities",
type: 'GET',
success: function(response) {
var parser = new ol.format.WMSCapabilities();
var result = parser.read(response);
var layersArray = result.Capability.Layer.Layer;
layersNameArray = [];
for(i=0;i<layersArray.length;i++){
layersNameArray.push(layersArray[i].Name)
}
return layersNameArray
}
});
}
You can make use of the Jquery callback feature,
make a call to your function this way,
getData(function(responsefromAjax){
alert('the response from ajax is :' +responsefromAjax);
// what ever logic that needs to run using this ajax data
});
And the make change to your method this way.
function getData(callback) { // passing the function as parameter
$.ajax({
url: "http://localhost:8080/geoserver/ows?service=wms&version=1.1.0&request=GetCapabilities",
type: 'GET',
success: function(response) {
var parser = new ol.format.WMSCapabilities();
var result = parser.read(response);
var layersArray = result.Capability.Layer.Layer;
layersNameArray = [];
for(i=0;i<layersArray.length;i++){
layersNameArray.push(layersArray[i].Name)
}
callback(layersNameArray); //this will execute your function defined during the function call. As you have passed the function as parameter.
}
});
}
Let me know if this helps

Uncaught TypeError: Cannot use 'in' operator to search for

I have this ajax json function where I use to send request and pull json response data (refer below)
//global array
var coaum_creation_date = [];
var coaum_arrears = [];
var coaum_wupdate= [];
var coaum_completed = [];
var coaum_pending = [];
var coaum_overdue = [];
//chart rendering
function get_coaum_chart(){
$.ajax({
url: $("body").attr("data-link") + "/get-coaum-chart",
type: 'post',
dataType: 'json',
data: { request : 'get coaum chart'},
beforeSend: function(){
},
success: function(response){
if(response.success){
console.log(response);
//clear the array objects
coaum_creation_date = [];
coaum_arrears = [];
coaum_wupdate= [];
$.each(response.chart_data, function(index, value){
coaum_creation_date.push(value.creation_date);
coaum_arrears.push(parseInt(value.arrears));
coaum_wupdate.push(parseInt(value.with_updates));
});
}
}
});
}
get_coaum_chart();
and there is the json response along the error (refer to the image below)
any ideas, clues, recommendations, suggestions, help?
Just guessing here, but it can be because you can use $.each on Objects, but your response.chart_data seems to be a JSON string.
Try using $.parseJSON() (doc):
$.each($.parseJSON(response.chart_data), ...
Hope it helps.

Clean way to make Subsequent AJAX Calls to API based on Data

So I have a conceptual question regarding the cleanest way to make subsequent AJAX calls to an API based on the returned data.
A quick example:
A function, which encompasses the call would look like this:
function makeCall(headers, min, max) {
$.ajax({
headers: headers,
url: "https://coolapi.com/data?begIndex" + min + "&endIndex=" + max + "&begTimestamp=1404198000000&endTimestamp=1409554800000",
type: "GET",
dataType: 'JSON'
});
}
makeCall(headers, 0, 20);
The beg / end index (min/max), determine the amount of data I'll get back in the array. The API will only return a maximum of 20 items in the array, but it will also return me a COUNT of how many items total exist in that array. An example of the data returned is below:
{
count = 133;
result = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19];
}
So my next call would be:
makeCall(headers, 20, 40);
and so on so forth, until I got all 133 items from the array.
The question is...what is the cleanest way to continue to make subsequent calls until I've gotten and stored all 133 items from the array? Given that the count could be any number, it's hard to imagine how I can do this. I was thinking of nesting more ajax calls in a "success" function, but it's not scalable if I get back a number like 300.
Does anyone have any advice on how to proceed?
Thanks in advance!
EDIT:
So based on the advice in the comment, I've attemped to make the call recursive--but it doesn't seem to function as intended:
var theData = [];
var minCounter=0;
var maxCounter= minCounter + 20;
function makeCall(headers, min, max) {
$.ajax({
headers: headers,
url: "https://coolapi.com/data?begIndex" + min + "&endIndex=" + max + "&begTimestamp=1404198000000&endTimestamp=1409554800000",
type: "GET",
dataType: 'JSON',
success: function (data) {
theData.push(data.result);
newMin = minCounter + 20;
if (data.count >= theData.length ) {
makeCall(headers, newMin, maxCounter);
}
}
});
}
makeCall(headers, minCounter, maxCounter);
How do properly increment the variable as well as set the flag?
SECOND EDIT:
The method below works using the second comment's suggestion, but there are some issues here as well...
function doAjax(headers, min, dObject) {
var max = min + 20;
$.ajax({
headers: headers,
url: "https://coolapi.com/data?begIndex" + min + "&endIndex=" + max + "&begTimestamp=1404198000000&endTimestamp=1409554800000",
type: "GET",
dataType: 'JSON',
success: function (data) {
results.push(data);
window.count = data.count;
dObject.resolve();
}
});
}
// array that will contain all deferred objects
var deferreds = [];
// array that will contain all results
var results = [];
// make the ajax calls
for (var i = 20; i < 133 ; i+= 20) {
var dObject = new $.Deferred();
deferreds.push(dObject);
doAjax(headers, i, dObject);
}
// check if all ajax calls have finished
$.when.apply($, deferreds).done(function() {
console.log(results);
});
var dObject = new $.Deferred();
doAjax(headers,0, dObject);
First, the data doesn't push to the array in order. There doesn't seem anyway to fix this. Also strangely enough, in the for loop--I have to set the number for it to actually work. Trying to store it in a variable doesn't seem to work as well...Suggestions here?
Here's a working implementation based around the code you started with. Code is commented to help you understand what is happening:
// Change these constants to suit your purposes.
var API_URL = 'https://coolapi.com/data';
var HEADERS = {};
var API_RESULTS_PER_REQUEST = 20;
var MAX_API_CALLS = 20;
// Count API calls to trigger MAX_API_CALLS safety lock.
var apiCalls = 0;
// Function we'll call to get all our data (see bottom).
function collectApiData(begTimestamp, endTimestamp) {
var dataReady = jQuery.Deferred();
var params = {
'begTimestamp': begTimestamp,
'endTimestamp': endTimestamp
};
var datasetsCollected = requestDatasets(params);
jQuery.when(datasetsCollected).then(function(data) {
dataReady.resolve(data);
});
return dataReady;
}
// Makes individual AJAX call to API
function callApi(params, headers) {
var $request = jQuery.ajax({
url: API_URL,
headers: headers,
data: params,
type: 'GET',
dataType: 'JSON'
});
return $request;
}
// Recursive function that makes API calls until data is collected, there is an
// error, or MAX_API_CALLS limit is hit.
function requestDatasets(params, resultsReady, resultsFetched) {
resultsReady = ( resultsReady !== undefined ) ? resultsReady : jQuery.Deferred();
resultsFetched = ( resultsFetched !== undefined ) ? resultsFetched : [];
// Trigger safety to avoid API abuse
if ( apiCalls >= MAX_API_CALLS ) {
console.error('Exceeded max API calls:', MAX_API_CALLS);
resultsReady.resolve(resultsFetched);
}
// Set index data
params.begIndex = resultsFetched.length;
params.endIndex = resultsFetched.length + API_RESULTS_PER_REQUEST;
// Request dataset from API
var apiRequest = callApi(params, HEADERS);
apiCalls += 1;
// Callback once API request has completed and data is ready
jQuery.when(apiRequest).done(function(data) {
var apiResultCount = data.count;
resultsFetched = resultsFetched.concat(data.result);
console.debug('Fetched', resultsFetched.length, 'of', apiResultCount, 'API results');
if ( apiResultCount > resultsFetched.length ) {
console.debug('Making another API call');
requestDatasets(params, resultsReady, resultsFetched);
}
else {
console.debug('Results all fetched!');
resultsReady.resolve(resultsFetched);
}
});
jQuery.when(apiRequest).fail(function(data) {
console.error('API error: returning current results.');
resultsReady.resolve(resultsFetched);
});
return resultsReady;
}
// Run script
var dataReady = collectApiData('1404198000000', '1409554800000');
jQuery.when(dataReady).then(function(data) {
console.log(data);
});
Here's a working fiddle that mocks the API using httpbin.org:
http://jsfiddle.net/klenwell/mfhLxun2/

Categories