Getting values from getJSON in right exec order - javascript

I'm getting this data dictionary from a db :
{"first":{"Head1":"6643Z","Head2":"1245Z"},"second":{"Head1":"1109E","Head2":"1231A"}}
and I need get only the first value for "Head1" record, for this I added a global var
in order to get the value out of the getJSON method, but run first the second alert
with a undefined value, and then run the first alert with the right value...
var message;
jQuery.getJSON("get_data.json", function(msg){
jQuery.each(msg,function (key,val){
message=val['string_data'];
return false;//trying to break
});
alert("first"+message);
});
alert("second"+message);
In order to this, how can I force have the right value on second alert, in other words,
how force to run the code in the right order....

The reason the second alert shows undefined is that when that code runs, the request hasn't completed yet.
You can make the getJSON synchronous, so that the alert doesn't run until the request is complete, but it leads to poor user experience (locks up the browser) and jQuery will be dropping support for it in an upcoming version. If you look at getJSON in the docs, you'll see it's just a wrapper that calls ajax, and if you use ajax you can specify an async: false option. (Note that this is true because you're using ajax with JSON; if it were JSON-P, you would have no synchronous option, as JSON-P is an asynchronous protocol.)
Your much better option is to embrace the asynchronous nature of web communication, and whatever you have that needs to use this data, have it supply a callback:
function getTheData(callback) {
jQuery.getJSON("get_data.json", function(msg){
var message, key;
for (key in msg) {
message = msg[key];
break; // <== SEE BELOW
}
callback(message);
});
}
getTheData(function(message) {
alert("second"+message);
});
Also note that the object you're getting back has no order, so your code getting the "first" value from it will be unreliable. You'll need to know the property key you're looking for in order to reliably get the value for that property. The order in which they appear in the text of the JSON has no effect on the order of the properties in the resulting object. (Arrays would, of course, be different.)
So for instance, if you always want the value for first, then:
function getTheData(callback) {
jQuery.getJSON("get_data.json", function(msg){
callback(msg.first);
});
}

Related

How to understand asynchronous Meteor.call on the client side

I'm working on a Meteor project and want to get the return value of Meteor.call in template helpers on client side. At very first, I just set a variable in the call back function and get the variable's value outside the Meteor.call. I found out the code after Meteor.call doesn't execute at all. Then I searched a bit and use Session, it works. But I don't really understand the reason. Here's my original code and modified code. Can anyone explain a bit for me? Thanks!!
Original wrong code: html
<div id="text-result-main">
<h2>{{title}}</h2>
</div>
js
Template.texts.helpers({
title: function(){
var index = Router.current().params.index;
Meteor.call('getTitle', index,function(error, result){
titles = result;
});
console.log(titles);
return titles;
}});
Collection text.js
Text = new Mongo.Collection("text");
Meteor.methods({
'getTitle': function(myindex){
return Text.findOne({index: myindex}).title;
}});
The working code: js
Template.texts.helpers({
title: function(){
var index = Router.current().params.index;
Meteor.call('getTitle', index,function(error, result){
Session.set("titles",result);
});
console.log(Session.get("titles"));
return Session.get("titles");
}});
Notice that I didn't publish Collection Text to the client at all because it's just so huge. Every time when I refresh the page when running the wrong code, I can't see the content of "title" or see it on the console. But when I set the session, it works. I don't really understand how it works here. Thanks
There is two issues Asynchronicity and Reactivity
This affectation
Meteor.call('getTitle', index,function(error, result){
titles = result;
});
inside the meteor call is executed but in a asynch way. So the return of your helper is immediately called, and return a empty value.
Try it out in the console of your browser.
But then, why your template render correctly with {{title}} when you use a Session Variable ?
It's because the Session is a reactive data source, witch means that every change to it trigger a re-computation of all templates involving this piece of data.
Here is a timeline:
Methods is called
Return empty value
Method is executed, setting variable value
If the Variable is a reactive data source, template is re-computed. ( in your case, the session is a reactive data source. )
To go further
I would use a reactive var in that case, it's very close from a session variable, but the scope is limited to a template.
A good read on Reactive data source: http://richsilv.github.io/meteor/meteor-reactive-data-types/
The problem is the fact that Meteor.call() is asynchronous when paired with a callback.
So when title() starts executing, it does not wait for your Meteor.call() invocation to return a result (or possibly an error). It continues execution. This is called asynchronous execution.
In short, you are trying to log the value for the key titles which doesn't exist in Session (since the state of your asynchronous Meteor call is unknown, at this point of time).
Try moving the console log statement into the callback paired with your Meteor.call() and you can see the result once it has successfully been set in Session.
A workaround to your problem is to make your Meteor.call() synchronous like this:
Template.texts.helpers({
title: function(){
var index = Router.current().params.index;
var result = Meteor.call('getTitle', index); // <--- this is synchronous code now
Session.set("titles",result);
console.log(Session.get("titles"));
return Session.get("titles");
}});
Removing the callback makes Meteor.call() behave synchronously.
If you do not pass a callback on the server, the method invocation
will block until the method is complete. It will eventually return the
return value of the method, or it will throw an exception if the
method threw an exception.
(from http://docs.meteor.com/api/methods.html#Meteor-call)
Why not use something like this:
title: function(){
var index = Router.current().params.index;
var a = Text.findOne({index: myindex}).title;
console.log(a);
return a;
without methods

console.log not printing the response

I have a function that calls another function over the server and returns a string back which i want to be printed in the browser's log windows, The function looks like:
function getErrorInfo() {
setTimeout(function () {
$.getJSON('Get/ErrorInfo', function (responseText) {
console.log("Log: "+responseText);
});
}, 5000);
}
getErrorInfo();
The function on the server sides does gets hits and returns a valid string But nothing is being displayed in the browser's windows Moreover the function on the server side must get hit after every 5 secs. but it only gets his on time and not again.
Please explain what am i doing wrong here.
Your basic issue is that you need to have properly formatted JSON in order to get back any result. Your result (per above) is:
3/8/2014 5:27:16 PMSystem.NullReferenceException: Object reference not set to an instance of an object. at movie.Models.Genre.GetPosts(Int32 min)
Not only is this an exception text, but it isn't valid JSON. JSON format is fully described here. Rather than calling a real service, I would recommend starting by just getting a static JSON file from the server. Then you know the data is correct.
Side Note:
The other issue here is how you print the OBJECT result from getJSON. When you try to print an object using "Console.log" it converts it to a string, which isn't probably going to show what you want. You should probably change your log statement to:
console.log(responseText);
In chrome at least, the console window will let you browse the contents of the object which can be really helpful. Between the note and the solution above I think you should have it. Best of luck!
When using $.getJSON(), the return result is required to be a valid JSON string, meaning it needs to be parsable into an object or array. In this situation, you can probably simply use $.get(), which will autodetect the return data type, or use $.ajax() and set the dataType: plain if you want to skip the JSON requirement.
On the second issue of keeping the log running, you can call getErrorInfo() from inside the setTimeout() or the callback, and it will keep running:
function getErrorInfo() {
setTimeout(function () {
$.getJSON('/echo/json/', function (responseText) {
console.log("Log: "+responseText);
getErrorInfo();
});
}, 5000);
}
getErrorInfo();
http://jsfiddle.net/Er5Lg/
In my opinion, in this situation, it is better than setInterval(), since that can get backed up and end up overriding calls, and the errors might display out of order.

javascript can't assign variable values due to asynchronous function.

In my JavaScript code below, I cannot get user_likes to take the value of response. I can Console output "response", and it has the values I need. However, when I try to Console output user_likes, I get undefined. What gives?
function fqlUserLikes(user_id) {
var user_likes;
FB.api(
{
method: 'fql.query',
query: 'SELECT page_id,name,type FROM page WHERE page_id IN (SELECT page_id FROM page_fan WHERE uid=' + user_id + ')'
},
function(response) {
user_likes=response;
}
);
Console.log(user_likes);
return user_likes;
}
Thanks for any help,
I.N.
Your method is asynchronous, so when you try to log and return the variable, it hasn't actually been assigned yet. Take the below snippet:
//Do what you need to do in here!
function(response) {
user_likes=response;
});
//The below code is executed before the callback above.
//Also, it should be console, and not Console. JS is case sensi.
Console.log(user_likes);
return user_likes;
Your function that changes the value of user_likes is not called immediately. FB.api() starts the process of calling the API, and then returns. Your console.log() call happens at this point, and then your function returns the user_likes value to its caller. Then, at some later point, the api call completes, your callback function is called, and it sets user_likes to the appropriate value. Unfortunately, there's nothing left to read that value.
You need to completely restructure your code to make it work. Javascript doesn't really support waiting for things to happen in the middle of code; it's a very asynchronous language. The best way is if you pass a callback function that actually uses the new value, rather than trying to store it in a variable for something else to read.

Global variables in jQuery plugin

I am creating a jquery plugin. In that am using some global variablse
$.rmtableparams.recordsCount: 0 is one of them.
I am assigned some values to this from one function inside an ajax call.
callAjax = function (surl, pselector, pi, rec) {
$.ajax({
..
success: function (data) {
$.rmtableparams.recordsCount =10;
}
});
}
But while I am trying to access $.rmtableparams.recordsCount in some other function it returns 0. But strange thing is that if i alert anything before that it will returns 10 correctly.
Ie: if my script is
alert("hi");
alert($.rmtableparams.recordsCount);
the second alert will shows 10
But if only alert($.rmtableparams.recordsCount); is there it returns 0
I was wondered with this. If any body knows the reason please help me.
The assignment $.rmtableparams.recordsCount =10; is inside the success callback of an $.ajax request. So the value isn't assigned until the ajax call is completed, and a response received. This happens fairly quickly, so while you're first alert is waiting to be closed, the ajax response is received, and the assignment is processed. Then, the second alert shows the new value.
If you leave out the first alert, the call is still being processed and the $.rmtableparams.recordsCount value hasn't changed yet.
It's as simple as that: AJAX stands for Asynchronous JavaScript And XML. Async is key, but often overlooked...
You can't just go ahead and set $.rmtableparams.recordsCount because $.rmtableparams doesn't exist.
You first need to set $.rmtableparams:
$.rmtableparams = {};
Then you go ahead and add data to the object:
$.rmtableparams.recordsCount = 10;
Make sure that the success callback is being fired. Add an alert or console.log inside the callback to do the check.

Initializing a variable declared outside of jQuery $.getJSON callback function

My script makes an Ajax request through jQuery. The data received is json_encoded via a server side script (php). This is further, stringified and then parseJSON'ed using jQuery to yield a recordCollection. I loop through recordCollection and push it onto records array, the variable that was declared outside the scope of the callback function.
The function looks like this:
var records = [] ;
$.getJSON(url, {id : recordid}, function(data) {
var recordCollection = jQuery.parseJSON(JSON.stringify(data));
$.each(recordCollection, function(){
records.push(this);
});
console.log(records) // displays all the objects, thus, the above code is right
});
console.log(records); // displays []
As you can notice above, the second time I logged records onto the console, it yielded an empty array, which is leading me to two conclusions:
Javascript arrays are passed by value, hence records outside the scope of the callback function does not retain it's value.
Ajax is asynchronous, hence records is being logged before the ajax call was complete and hence it still retains the value of the empty uninitialized records array and is logging that onto the console.
Now if 1 is true, how can I initialize the records array ?
And if 2 is true, should I make this Ajax call synchronous? This will make javascript block until the value is returned and thus the second time records array is logged onto the console, it will display the updated value of the array ?
The third is that I am completely missing a trick and doing something really dumb here.
I do need the records array to be set with the data returned from the ajax call as it needs to be passed around to different javascript functions in the script and the DOM basically waits for this result to load the data.
Thanks guys!
You are correct in that, ajax calls are async, hence Asynchronous Javascript and XML. You can make it sync, but you shouldn't because your array will then be available for anyone to play with, which can cause some big headaches.
Instead, have an init call that is run once your ajax call is completed.
function callback(records) {
// do stuff with records.
}
$.getJSON(url, {id : recordid}, function(data) {
var recordCollection = jQuery.parseJSON(JSON.stringify(data));
callback(recordCollection);
});
Ajax stands for Asynchronous JavaScript and XML (forget the XML part) so i think you can guess what is right ;-)
I added the execution order with comments:
var records = [] ;
// 1. send request and return immediately
$.getJSON(url, {id : recordid}, function(data) {
// 3. response from server is received
var recordCollection = jQuery.parseJSON(JSON.stringify(data));
$.each(recordCollection, function(){
records.push(this);
});
console.log(records)
});
// 2. print records
console.log(records);
You should not try to make the request synchronous in any way. If you need to do something with records after the data is available you should create a new function and call it after you pushed the values into records.

Categories