Return value from Ajax callback? - javascript

I have a JavaScript class that handles queries to a local DB (on a WebOs device). Now what I want to do is, create a model with all my basic queries to simplify my code.
So first I create a function:
getLists: function(){
this.query( 'SELECT * FROM lists ORDER BY rowID DESC', {
onSuccess: enyo.bind(this,function(data) { this.getData(data); } ),
onError: function() { return false; } } );
}
And than I have my callback function which receives the data:
getData: function(data){
return data;
}
Now what I would like to do, is call it like this from my app:
var data = getLists();
The problem is, this is not returning the data from my callback function (getData). My question is how can I have "getLists" return the data from the callback?
Thank you

You're thinking imperial: C follows B follows A. Forget about that.
AJAX and modern JavaScript works differently. You never say "get data now", you say "call X when data is available".
So the solution is to write some code which does something useful with the data. Let's call this function a. Instead of:
var data = conn.getData();
a( data );
b( data );
c( data );
you do
conn.getData( a ); // a has to call b which calls c.
Eventually, the data will be there and a will be called with data as an argument.
See? You don't chain calls to a() and b() as in traditional programming. Instead, you create functions that do what you want and pass those functions around.

You don't get to. The first A in AJAX is Asynchronous. The requests happen "out of time" with the other processing. Your call to getLists returns after it launches the AJAX request, and the callback function is called when the remote server responds to the AJAX request.
-- Edited for comments --
If you want to "watch" a variable you can use something like this:
// Set up a container for the data to return to.
var retData;
// Modify the getData function to assign to the global variable
getData: function (data) {
retData = data;
}
// Start the "wait" process.
var myInterval = setInterval(function () {
if (retData == undefined) {
return;
}
// when the return data shows up stop waiting.
clearInterval(myInterval);
// some other data processing here in this function
// or trigger the actual processing function.
// don't have to pass retData to it, it's global, the
// data handler function can retrieve it itself.
myDataHandler();
}, 1000);
// make the ajax call here.
getLists();

Related

getJson returns undefined value instead of Json object

I am trying to use simple getJson call to get Json object from server.
On server side everything looks good. Json is created and returned:
But on the front-end my object is not mapped to returned Json from server. It is undefined in first call and that value and then it goes one more time through getJson and returns real object.
This is my code:
btnSaveNewMeeting.onclick = function () {
var vm = {
'Title': $('#eventTitle').val(),
'StartAt': $('#startdatepicker').val() + ' ' + $('#starttimepicker').val(),
'EndAt': $('#enddatepicker').val() + ' ' + $('#endtimepicker').val()
}
var meetings = GetAllScheduledMeetings();
if (CheckIfMeetingsAreOverlapping(vm.StartAt, vm.EndAt, meetings)) {
addNewMeetingModal.style.display = "none";
$.ajax({
type: 'POST',
url: "/Meeting/Create",
data: vm,
success: function () {
$('#calendar').fullCalendar('refetchEvents');
}
});
ClearPopupFormValues();
}
}
So I want to get value from GetAllScheduledMeetings(); and put it in meetings object.
var meetings = GetAllScheduledMeetings();
function GetAllScheduledMeetings() {
$.getJSON("/Meeting/GetAllScheduledMeetings", function (result) {
return result;
});
}
So GetAllScheduledMeetings() should only make a call to server and return result. But that doesn't happened.
When I debug in console of a browser what is happening is this:
1. on button click GetAllScheduledMeetings() gets invoked.
2. getJson makes a call to server and json object is created there and returned.
3. it goes back to front-end but skips whole return result; part and returns undefine value to var meeting = GetAllScheduledMeetings();
4. I get few exceptions because meeting is undefine
5. GetAllScheduledMeetings() gets called again for some reason, after all of this has happened and in this call result gets real values from server.
Does someone knows why is this happening? Why two calls are made and why in the first call I do not get data from server?
GetAllScheduledMeetings never returns anything (so, returns undefined) and "is async", so, at the moment of execution, when using meetings, there is a very high probabilty for the variable to be undefined.
You'll need to recode GetAllScheduledMeetings to pass you all "if block" as a callback or use any other way to work with async code (Promises for instance).
function GetAllScheduledMeetings() {
$.getJSON("/Meeting/GetAllScheduledMeetings", function (result) { // This anonymous function is called asynchronously and returns result *in the blue*
return result;
});
// GetAllScheduledMeetings doesn't specify a return value so it's retVal is undefined
}
SOLUTION:
Since $.getJSON or $.ajax calls are asynchronous by default all you need to do is make them synchronous by adding: async: false to call definition.

how to call a get web service from javascript when the data returned by web changes?

I am trying to call a web-service with in javascript and get the data from web-service.
I want to trigger the ajax call again when the data returned by web services changes.
Here is code i tried with, but failed to trigger callback again when data from server changes.
var request=$.get("http://localhost:8080/messanger/webresources/myresource",function(data){
if(data=="something"){
//do something
}
else if(data=="something else"){
//do something else
}
});
When the data from web-services changes, i want to execute the get request again!!!
Please suggest the concept to do this...
I would suggest recursive call of function that calls the service. It is beeing called just as long as the result differs from the previous one. But im still not sure if it is what zou want:)
var previousResult = null;
function callMyService() {
var request = $.get("http://localhost:8080/messanger/webresources/myresource", function (data) {
if (data == previousResult) {
// returned data is the same as last call
}
else {
// save the previous result to global variable
previousResult = data;
// recursive call
callMyService();
}
});
}
Then call is wherever you need to:
callMyService()

Can't get Ajax response

I am using javascript and php to run an Ajax code.
The result at the moment is undefined.
I am using localStorage to move the variable from the Ajax function because I cannot understand the use of a callback (I have followed numerous examples of using callbacks but none ever worked. I figured this solution might be the least complex.
Javascript:
$( document ).ready(function() {
$('#submit-values').click(function(e){
/************************************************************* SUBMIT */
e.preventDefault();//Stop page reload on click
$('#put-output-here').val(createParagraph());
});
function createParagraph(){
createSentence();
return localStorage.getItem('sentence');
}
function createSentence(){
$.when(ajax1()).done(function(a1){
localStorage.setItem('sentence', a1);
})
}
function ajax1(){
$.post("word-engine.php",
{
},
function(data){
});
}
});
PHP:
<?php
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$randomString = '';
for($x = 0; $x < 10; $x++){
$rand = rand(0,62);
$randomString = $randomString.$chars[$rand];
}
echo $randomString;
?>
At the moment my result is undefined
use this: since $.post is a asynchronous function. The control from function will immediately return after it run post but the response from post may be received later.
function ajax1(){
$.post("word-engine.php",
{
},
function(data){
setdata(data);
});
}
function setdata(data){
localStorage.setItem('sentence', data);
}
note: for more info see this post:why cant I return data from $.post (jquery)
You need the done event on the $.post function not on the function that's wrapping that function.
E.g.
$.post( "word-engine.php", function( data ) {
localStorage.setItem('sentence', data );
});
On 'done'/return of the ajax post it will put the returned value into your localStorage 'sentence' key. The first param of the post function is the URL of the endpoint, the next is the success handler function. You can then specify more including the callback function handler for failure etc. See docs here for more information.
#suchit makes a good point, you won't be able to access the value in localStorage straight away because post is an async event, the javascript code will move on and the callback will happen when the response is received. You're best displaying your returned localStorage variable to screen inside the success handler or trigger whatever needs to happen with it from there.

getJSON jQuery won't fill object

So I've got some code that retrieves a series of objects from an API. When I try to store them in a global variable, it doesn't seem to do anything. Here's the code:
var current_corpus = {};
function page_init() {
$.getJSON("http://resource1.com", function(data) {
populate_collections(data);
populate_citations(data);
});
}
function populate_collections(collections) {
$.each(collections, function (i, item) {
current_corpus[item] = [];
});
}
function populate_citations(collections) {
$.each(collections, function (index, collection) {
$.getJSON("http://resource2.com/" + collection.collection_id, function(data) {
current_corpus[collection] = data;
console.log(current_corpus);
});
});
}
When this finishes, current_corpus is completely empty. Logging these items verifies that they're being returned from the resources I'm posting to. I think there's just something about the asynchronous nature of these calls that I'm missing.
The line
current_corpus[item] = [];
is superfluous I think as the line
current_corpus[collection] = data;
should do the same thing while also tying data to the key object. Either way at the end of these functions running trying to access current_corpus via the console just gives me back an empty object.
Resources for dealing with AJAX stuff like this would be appreciated as well.
It all depends on what you want to do when the ajax requests complete. The A in ajax stands for Asynchronous meaning that such requests are non-blocking -- i.e. they will run in the background as control moves to the next line. Which explains why you're seeing an empty object right after the functions that invoke the ajax requests.
You can confirm that your code is working fine or you can do something once all the requests complete by using the following code snippet:
$(function() {
$(document).on('ajaxStop', function() {
console.log( current_corpus );
//do something with the now fully constructed object
});
});

Pass additional parameter to a JSONP callback

For a project of mine I need to do multiple calls to a (remote) API using JSONP for processing the API response. All calls use the same callback function. All the calls are generated dynamically on the client's side using JavaScript.
The problem is as follows: How do I pass additional parameters to that callback function in order to tell the function about the request parameters I used. So, e.g., in the following example, I need the myCallback function to know about id=123.
<script src="http://remote.host.com/api?id=123&jsonp=myCallback"></script>
Is there any way to achieve this without having to create a separate callback function for each of my calls? A vanilla JavaScript solution is preferred.
EDIT:
After the first comments and answers the following points came up:
I do not have any control over the remote server. So adding the parameter to the response is not an option.
I fire up multiple request concurrently, so any variable to store my parameters does not solve the problem.
I know, that I can create multiple callbacks on the fly and assign them. But the question is, whether I can avoid this somehow. This would be my fallback plan, if no other solutions pop up.
Your options are as follows:
Have the server put the ID into the response. This is the cleanest, but often you cannot change the server code.
If you can guarantee that there is never more than one JSONP call involving the ID inflight at once, then you can just stuff the ID value into a global variable and when the callback is called, fetch the id value from the global variable. This is simple, but brittle because if there are every more than one JSONP call involving the ID in process at the same time, they will step on each other and something will not work.
Generate a unique function name for each JSONP call and use a function closure associated with that function name to connect the id to the callback.
Here's an example of the third option.
You can use a closure to keep track of the variable for you, but since you can have multiple JSON calls in flight at the same time, you have to use a dynamically generated globally accessible function name that is unique for each successive JSONP call. It can work like this:
Suppose your function that generate the tag for the JSONP is something like this (you substitute whatever you're using now):
function doJSONP(url, callbackFuncName) {
var fullURL = url + "&" + callbackFuncName;
// generate the script tag here
}
Then, you could have another function outside of it that does this:
// global var
var jsonpCallbacks = {cntr: 0};
function getDataForId(url, id, fn) {
// create a globally unique function name
var name = "fn" + jsonpCallbacks.cntr++;
// put that function in a globally accessible place for JSONP to call
jsonpCallbacks[name] = function() {
// upon success, remove the name
delete jsonpCallbacks[name];
// now call the desired callback internally and pass it the id
var args = Array.prototype.slice.call(arguments);
args.unshift(id);
fn.apply(this, args);
}
doJSONP(url, "jsonpCallbacks." + name);
}
Your main code would call getDataForId() and the callback passed to it would be passed the id value like this followed by whatever other arguments the JSONP had on the function:
getDataForId(123, "http://remote.host.com/api?id=123", function(id, /* other args here*/) {
// you can process the returned data here with id available as the argument
});
There's a easier way.
Append the parameter to your url after '?'. And access it in the callback function as follows.
var url = "yourURL";
url += "?"+"yourparameter";
$.jsonp({
url: url,
cache: true,
callbackParameter: "callback",
callback: "cb",
success: onreceive,
error: function () {
console.log("data error");
}
});
And the call back function as follows
function onreceive(response,temp,k){
var data = k.url.split("?");
alert(data[1]); //gives out your parameter
}
Note: You can append the parameter in a better way in the URL if you already have other parameters in the URL. I have shown a quick dirty solution here.
Since it seems I can't comment, I have to write an answer. I've followed the instructions by jfriend00 for my case but did not receive the actual response from the server in my callback. What I ended up doing was this:
var callbacks = {};
function doJsonCallWithExtraParams(url, id, renderCallBack) {
var safeId = id.replace(/[\.\-]/g, "_");
url = url + "?callback=callbacks." + safeId;
var s = document.createElement("script");
s.setAttribute("type", "text/javascript");
s.setAttribute("src", url);
callbacks[safeId] = function() {
delete callbacks[safeId];
var data = arguments[0];
var node = document.getElementById(id);
if (data && data.status == "200" && data.value) {
renderCallBack(data, node);
}
else {
data.value = "(error)";
renderCallBack(data, node);
}
document.body.removeChild(s);
};
document.body.appendChild(s);
}
Essentially, I compacted goJSONP and getDataForUrl into 1 function which writes the script tag (and removes it later) as well as not use the "unshift" function since that seemed to remove the server's response from the args array. So I just extract the data and call my callback with the arguments available. Another difference here is, I re-use the callback names, I might change that to completely unique names with a counter.
What's missing as of now is timeout handling. I'll probably start a timer and check for existence of the callback function. If it exists it hasn't removed itself so it's a timeout and I can act accordingly.
This is a year old now, but I think jfriend00 was on the right track, although it's simpler than all that - use a closure still, just, when specifying the callback add the param:
http://url.to.some.service?callback=myFunc('optA')
http://url.to.some.service?callback=myFunc('optB')
Then use a closure to pass it through:
function myFunc (opt) {
var myOpt = opt; // will be optA or optB
return function (data) {
if (opt == 'optA') {
// do something with the data
}
else if (opt == 'optB') {
// do something else with the data
}
}
}

Categories

Resources