I have created a small JavaScript application with the following function that calls a function to retrieve JSON data:
var months = function getMonths(){
$.getJSON("app/data/Cars/12Months", function (some_data) {
if (some_data == null) {
return false;
}
var months_data = new Array();
var value_data = new Array();
$.each(some_data, function(index, value) {
months_data.push(index);
value_data.push(value);
});
return[months_data,value_data];
});
}
I have then created, in the same file, another function that does something when a specific page is loaded. In this function the variable 'months' is passed to the variable 'result'.
$(document).on('pageshow', '#chartCar', function(){
$(document).ready(function() {
var result = months;
var date = result[0];
var values = result[1];
//more code here...
});
}
the problem is that, based on the debugger, the getMonths() function works fine and produces the expected output, but the 'result' variable in the second function can't obtain the values passed to it by the variable 'months'. Do you know how to solve this issue?
The problem is that you $.getJSON() function is asynchronous, so your data gets loaded later then you read it. There're two workarounds:
1. Replace your $.getJSON with $.ajax and setting async: false;
2. Put your code in $.getJSON callback:
var months = function getMonths(){
$.getJSON("app/data/Cars/12Months", function (some_data) {
if (some_data == null) {
return false;
}
var months_data = new Array();
var value_data = new Array();
$.each(some_data, function(index, value) {
months_data.push(index);
value_data.push(value);
});
var date = months_data;
var values = value_data;
//more code here..
})
}
There must be a syntax error.
replace
});
}
With
});
});
$.getJSON() is a wrapper around $.ajax which is async by default. But you treat it like a sync call.
You can use $.ajaxSetup()
$.ajaxSetup( { "async": false } );
$.getJSON(...)
$.ajaxSetup( { "async": true } );
or use $.ajax with async: false
$.ajax({
type: 'GET',
url: 'app/data/Cars/12Months',
dataType: 'json',
async: false,
success: function(some_data) {
//your code goes here
}
});
or if possible change the behavior of your app so that you process your data in a callback function.
Related
I need to execute 3 ajax requests. I know that they happen to be asynchronous by default (And making them synchronous messes up the VM, so I don't want to go that way.) The way I do it is by calling a function three times passing variables.
result = '';
parse(var1);
parse(var2);
parse(var3);
view();
function parse(variable) {
//ajax request here
$.ajax({
type: 'POST',
url: 'script.php',
data: {variable: variable},
success: function (data) {
//result stored in a global variable
result += data;
}
});
}
function view() {
//do something with result
}
But right now, the view() is triggered right away when the result isn't done cooking. How do I set them up to happen one after the other? I read about callbacks but they are very confusing since I don't have 3 distinct functions but just one taking different variables.
You could store your variables in an array and use a function to make your ajax call:
var variables = [var1, var2, var3];
function callParse() {
if(variables.length) {
var currentVar = variables.shift();
parse(currentVar);
}
else {
view();
}
}
function parse(variable){
//ajax request here
$.ajax({
type:"POST",
url:'script.php',
data:{variable:variable},
success:function(data)
{
result+=data;
callParse();
}
});
}
function view(){
//do something with result
}
Try chained promises - from: https://css-tricks.com/multiple-simultaneous-ajax-requests-one-callback-jquery/
$.when(
// Get the HTML
$.get("/feature/", function(html) {
globalStore.html = html;
}),
// Get the CSS
$.get("/assets/feature.css", function(css) {
globalStore.css = css;
}),
// Get the JS
$.getScript("/assets/feature.js")
).then(function() {
// All is ready now, so...
// Add CSS to page
$("<style />").html(globalStore.css).appendTo("head");
// Add HTML to page
$("body").append(globalStore.html);
});
You could try doing it this way:
parseAndView([var1, var2, var3]);
function parseAndView(vars, index) {
index = index || 0; //initialize index if not passed
//execute the AJAX call only if there are more variables to parse
if (index < vars.length)
//ajax request here
$.ajax({
type: "POST",
url: 'script.php',
data: {variable: vars[index]},
success: function (data) {
// result stored in a global variable
result += data;
// recursive call to parse another variable
parseAndView(vars, index++);
}
});
else
view();
}
function view() {
//do something with result
}
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
I was wondering if there is a way to pull and use JSON data from two different sources. Currently, the code looks like this:
//JSON1
$.getJSON('url1',function(data){
$.each(data,function(key,val){
//code
});
});
//JSON2
$.getJSON('url2',function(data){
$.each(data,function(key,val){
//code
});
});
When I do this, i seems that variables created from one JSON function aren't available in the other one, which makes it hard for them to be useful together.
Is there a better way to have these two work together?
This function takes an array of urls and a callback as parameters:
function getMultiJSON(urlList,callback) {
var respList = {};
var doneCount = 0;
for(var x = 0; x < urlList.length; x++) {
(function(url){
$.getJSON(url,function(data){
respList[url] = data;
doneCount++;
if(doneCount === urlList.length) {
callback(respList);
}
});
})(urlList[x]);
}
}
You would use it like this:
getMultiJSON(['url1','url2'],function(response) {
// in this case response would have 2 properties,
//
// response.url1 data for url1
// response.url2 data for url2
// continue logic here
});
You might want to add a timeout as the function will never call your handler should any of the URLs fail to load
Variable declared within the functions using var (or blocks, using let) are not available outside of the functions (or blocks).
$.getJSON('url1',function(data){
$.each(data,function(key,val){
var only_accessible_here = key;
});
});
So if you want variables that are accessible outside the scope of the function they are declared in, you need to declare them outside of the function they are used in.
var combined_stuff = ''
$.getJSON('url1',function(data){
$.each(data,function(key,val){
combined_stuff += val;
});
});
//JSON2
$.getJSON('url2',function(data){
$.each(data,function(key,val){
combined_stuff += val;
});
});
As Marc B says, there is no way to know which order the combined_stuff variable will be updated, either by JSON1 first, or by JSON2 first, or by only one, if one of the getJSON calls fail, or by neither if both fail.
If the order of updating is important, call the one you want to use second in the function of the one you want to call first.
var combined_stuff = ''
$.getJSON('url1',function(data){
$.each(data,function(key,val){
combined_stuff += val;
//JSON2
$.getJSON('url2',function(data){
$.each(data,function(key,val){
combined_stuff += val;
});
});
});
});
Easily using the open source project jinqJs (http://www.jinqJs.com)
var data1 = jinqJs().from('http://....').select();
var data2 = jinqJs().from('http://....').select();
var result = jinqJs().from(data1, data2).select();
The example does a sync call, you can do an async call by doing something like this:
var data1 = null;
jinqJs().from('http://....', function(self){ data1 = self.select(); });
Result will contain both results combined.
If you control the endpoint, you could make it return all of the data you want in one shot. Then your data would look like:
{
"url1_data": url1_json_data,
"url2_data": url2_json_data
}
If you still have 2 endpoints you need to hit, you can pass the result of your first ajax call to the second function (but this makes your 2 ajax calls synchronous):
function getJson1(){
$.getJSON('url1',function(data){
getJson2(data);
});
}
function getJson2(json1Data){
$.getJSON('url2',function(data){
//Do stuff with json1 and json2 data
});
}
getJson1();
I would recommend you to use $.when function available in jquery to execute both the methods in parallel and then take the action. See the code snipped below,
var json1 = [], json2 = [];
$.when(GetJson1(), GetJson2()).always(function () {
//this code will execute only after getjson1 and getjson2 methods are run executed
if (json1.length > 0)
{
$.each(json1,function(key,val){
//code
});
}
if (json2.length > 0)
{
$.each(json2,function(key,val){
//code
});
}
});
function GetJson1()
{
return $.ajax({
url: 'url1',
type: 'GET',
dataType: 'json',
success: function (data, textStatus, xhr) {
if (data != null) {
json1 = data;
}
},
error: function (xhr, textStatus, errorThrown) {
json1 = [];//just initialize to avoid js error
}
}
function GetJson2()
{
return $.ajax({
url: 'url2',
type: 'GET',
dataType: 'json',
success: function (data, textStatus, xhr) {
if (data != null) {
json2 = data;
}
},
error: function (xhr, textStatus, errorThrown) {
json2 = [];//just initialize to avoid js error
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
The returned data from each AJAX call are not available outside its own callback function. I'm sure there are more elegant (complex?) solutions, but a couple of simple, Occamic, solutions include global variables, or storing the received data in hidden input elements.
Within each callback function, just loop until the data from the other call is present:
function getJson1(){
$.getJSON('url1',function(data){
var d2 = '';
$('#hidden1').val(data);
while ( d2 == '' ){
//you should use a time delay here
d2 = $('#hidden2').val();
}
getJson2();
});
}
function getJson2(){
$.getJSON('url2',function(d2){
var d1 = '';
$('#hidden2').val(d2);
while ( d1 == '' ){
//you should use a time delay here
d1 = $('#hidden1').val();
}
//Do stuff with json1 and json2 data
});
}
getJson1();
I am creating new functionality where I build a grid based on Json data returned from Ajax. I have decided I want to encapsulate this functionality within a function, so when I add/update/delete, I can on success retrieve a new representation of the data.
The problem I am having is I want to fill a global array but once my function that uses AJAX ends, I have an Array but no data. This isn't a problem when all the code is within the AJAX call but once I try to separate this in to its own function, it doesn't work as intended.
<script type="text/javascript">
var DataArray = [];
// Use this function to fill array
function retrieveNotes() {
$.ajax({
url: "http://wks52025:82/WcfDataService.svc/GetNotesFromView()?$format=json",
type: "get",
datatype: "json",
asynch:true,
success: function (data) {
returnedData = data;
$.each(data.d, function (i, item) {
DataArray[i] = [];
DataArray[i][0] = item.NotesTitle.trim();
DataArray[i][1] = item.ProfileName.trim();
DataArray[i][2] = item.IsShared;
DataArray[i][3] = item.NameOfUser.trim();
}) // End of each loop
}
});
}
$(document).ready(function () {
retrieveNotes();
DataArray;
</script>
It's asynchronous, so you'll have to wait for the ajax call to finish before you can use the data :
function retrieveNotes() {
return $.ajax({
url: "http://wks52025:82/WcfDataService.svc/GetNotesFromView()?$format=json",
type: "get",
datatype: "json"
});
}
$(document).ready(function () {
retrieveNotes().done(function(data) {
var DataArray = [];
$.each(data.d, function (i, item) {
DataArray[i] = [];
DataArray[i][0] = item.NotesTitle.trim();
DataArray[i][1] = item.ProfileName.trim();
DataArray[i][2] = item.IsShared;
DataArray[i][3] = item.NameOfUser.trim();
});
// you can only use the data inside the done() handler,
// when the call has completed and the data is returned
});
});
I have an issue with a method ive created for an object ive created. one of the methods requires a callback to another method. the problem is i cant add the data to the object that called the method. it keeps coming back as undefined. otherwise when i send the data to the console it is correct. how can i get the data back to the method?
var blogObject = new Object();
var following = [...];
//get posts from those blogs
blogObject.getPosts = function () {
var followersBlogArray = new Array();
for (var i = 0; i < this.following.length;i++){
var followersBlog = new Object();
// get construct blog url
var complete_blog_url = ...;
i call the getAvatar function here sending the current user on the following array with it.
followersBlog.avatar = blogObject.getAvatar(this.following[i]);
that part goes smoothly
followersBlogArray.push(followersBlog);
}
this.followersBlogArray = followersBlogArray;
}
here is the function that gets called with the current user in following array
this function calls an ajax function
blogObject.getAvatar = function (data) {
console.log("get avatar");
var url = "..."
this ajax function does its work and has a callback function of showAvatar
$(function() {
$.ajax({
type: "GET",
dataType: "jsonp",
cache: false,
url: url,
data: {
jsonp:"blogObject.showAvatar"
}
});
});
}
this function gets called no problem when getAvatar is called. i cant however get it to add the data to the followersBlog object.
blogObject.showAvatar = function (avatar) {
return avatar
}
everything in here works fine but i cant get the showAvatar function to add to my followersBlog object. ive tried
blogObject.showAvatar = function (avatar) {
this.followersBlog.avatar = avatar;
return avatar
}
that didnt work of course. it shows up as undefined. can anyone help?
so somethings like...
$(function() {
$.ajax({
type: "GET",
dataType: "jsonp",
cache: false,
url: url,
complete: function () {
this.avatar = data;
}
data: {
jsonp:"blogObject.showAvatar"
}
});
});
}
Welcome to the world of asynchronous programming.
You need to account for the fact that $.ajax() will not return a value immediately, and Javascript engines will not wait for it to complete before moving on to the next line of code.
To fix this, you'll need to refactor your code and provide a callback for your AJAX call, which will call the code that you want to execute upon receiving a response from $.ajax(). This callback should be passed in as the complete argument for $.ajax().
The correct option for setting the JSONP callback is jsonpCallback. The recommendation from the API for .ajax(...) is to set it as a function.
{
// ...
jsonpCallback: function (returnedData) {
blogObject.showAvatar(returnedData);
},
// ...
}