Cannot parse JSON? - javascript

Here's my javascript file
var callAjax = function(relative_path){
var Ajax = new XMLHttpRequest();
Ajax.onreadystatechange = function() {
//Since what we are calling a local file. we cannot get a 200 OK Status.
//So We check only the readystate
if(Ajax.readyState==4){
serialized = Ajax.responseText;
alert(serialized);
// ^^ alerts fine.
return serialized;
}
}
Ajax.open("GET",relative_path, true);
Ajax.send();
};
var readSettings = function(){
var data = callAjax('settings.json');
obj = JSON.parse(data);
alert(obj);
}
Now when i call readSettings() somewhere in my html, the first alert (in the callAjax functions alerts the JSON correctly. but the second one does not. When i see the console, the error is :
[21:04:02.233] SyntaxError: JSON.parse: unexpected character # file:///home/cipher/Codes/looma-f5/js/looma.js:23
My settings.json is:
{
"classes": 8,
"config": "classConfig",
"locale": {
"en": "localeEn"
},
"defaultLocale": "en"
}
I ran the JSON through online tools, it looks good. Why is firefox not parsing these?

You're not returning any value from the callAjax function. You need to put your code that uses the result inside the onreadystatchange handler.
You do have a return statement, but it's inside the callback, which returns to the internal caller of the callback, and which is invoked after your callAjax returned.
Since it seems that callAjax is fairly generic, a good approach is to have that function accept a callback as an argument, then invoke it, passing in the response.
// receive a callback----vv
var callAjax = function(relative_path, callback){
var Ajax = new XMLHttpRequest();
Ajax.onreadystatechange = function() {
if(Ajax.readyState==4){
serialized = Ajax.responseText;
alert(serialized);
// vv---invoke the callback
callback(serialized);
}
}
Ajax.open("GET",relative_path, true);
Ajax.send();
};
var readSettings = function(){
// pass a callback ----------------------vv
var data = callAjax('settings.json', function(data) {
var obj = JSON.parse(data);
alert(obj);
});
}
If the caller of readSettings needs to work with the response, then you could have readSettings also receive a callback, and then either pass it on directly, or wrap it in another function so that it can first do the parsing.
I'll give an example that assumes that it needs to be wrapped.
// receive a callback----------vv
var readSettings = function(callback){
// pass a callback that wraps the first---vv
var data = callAjax('settings.json', function(data) {
// parse the response data
var obj = JSON.parse(data);
// invoke the callback, passing it the parsed object
callback(obj);
});
}
readSettings(function(settings_obj) {
alert(settings_obj);
});

The problem is that you can JSON.parse immediately after callAjax returns. Before the onreadystate callback is executed. Due to asynchronous nature of the operation you should trigger parsing from the callback.

The "A" in AJAX is for asynchronous. After submitting the XMLHttpRequest, the callAjax function will return immediately, without waiting for the request to complete. Thus, the JSON.parse will be called with the return value of callAjax (which isn't the JSON you're looking for), generating the error.
Some time later, the XMLHttpRequest will complete and the onreadystatechange callback will be run. You return the JSON from this function, but the JSON doesn't go anywhere because it's returning from the callback, not from callAjax.
You must perform the JSON parsing and subsequent activities as a result of the onreadystatechange event.

Related

Ready state is still 1 though I got the Response

toggleCompletedCheck : function(e) {
e.stopPropagation();
e.stopImmediatePropagation();
var key = $(e.currentTarget).attr("id");
this.model = todoCollection.findWhere({
key : key
});
this.model.toggle("completed", true);
this.option.collection = todoCollection.add(this.model);
var email = this.model.get("email");
var title = this.model.get("title");
var key = this.model.get("key");
var status = this.model.get("status");
var completed = this.model.get("completed");
this.updateUserData(email, key, title, completed, status);
returnValue = this.model.save();
console.log(returnValue);
},
The ready state is still 1 with in the function. The variable which I used is a window object(returnValue). When I print the object again in the console(from chrome browser) it shows me ready state 4 also allows me to access the responseText using returnValue.responseText. I am using the backbone.js to save the input to the backend. That returns the responseText as saved. But in turn, I am unable to access it when I try to it says undefined. How to get the responseText that I needed with in this function.
Backbone's model.save() method is asyncronous. It returns a value (the javascript xhr object), but the request is not complete at return time.
To use the completed response, you would usually pass success or error callbacks to the save method (docs here):
this.model.save(null, {
success: function(model, response, options) {
// do something with the response
},
error: function(model, response, options) {
// do something with the response
}
});
This can be a bit of an adjustment when you are used to returning responses from your functions, but equivalent functionality is almost always possible using callbacks.

How do I pass a variable to request's callback?

I'm using express and request to turn a site's html into json, then returning it. For example:
app.get('/live', function(req,_res){
res = _res;
options.url = 'http://targetsite.com';
request(options,parseLive);
});
function parseLive(err, resp, html) {
var ret = {status:'ok'};
-- error checking and parsing of html --
res.send(ret);
}
Currently I'm using a global var res to keep track of the return call, but this fails when multiple requests are made at the same time. So, I need some way of matching return calls from express to their callbacks in request.
How might I do this?
Use a closure.
Pass the variable to a function. Return the function you want to pass to request from that function.
app.get('/live', function(req,_res){
options.url = 'http://targetsite.com';
request(options,parseLiveFactory(res));
});
function parseLiveFactory(res) {
function parseLive(err, resp, html) {
var ret = {status:'ok'};
-- error checking and parsing of html --
res.send(ret);
}
return parseLive;
}

ajax complete callback function is never called

I'm using Django.
I have the following code
var done_cancel_order = function(res, status) {
alert("xpto");
};
var cancel_order = function() {
data = {};
var args = {
type:"GET",
url:"/exchange/cancel_order/"+this.id,
data:data,
complete:done_cancel_order
};
$.ajax(args);
return false;
};
The function var cancel_order is called when I press a button on the page. That url when accessed is does some things on the server side, which I can check indeed are done, and then returns a json specifying whether or not the request was successful. You get:
{'status':200, 'message':'order canceled'}
The problem is that the callback is never called. I would like to have the callback display to the user the thing that was returned from the server. But even the first alert("xpto") inside the callback is never executed. Why is that?
EDIT:
I have checked that this code:
var cancel_order = function() {
data = {};
var args = {
type:"GET",
url:"/exchange/cancel_order/"+this.id,
data:data,
complete: function() { alert("xpto"); }
};
$.ajax(args);
return false;
};
displays the same behavior as described above: everything goes great on the server side, but the callback isn't called.
Be sure nothing is messing with your debug tools [e.g. console.log], it may end up wrecking your js code, delivering unexpected results.
Why don't you change it to this:
function done_cancel_order (res, status) {
/* remains same */
};
I hope, this one would work for you!
Or just simply:
complete: alert("xpto");

JavaScript function within a function - returning an object

I would like to call a function within a function and have this inner function return an object. I am using a JSONRequest function that I created myself so just assume that the request fetches an array of roles. Here is the code:
(users = function(){
this.getUserRoles = function(){
var params = {};
var json = new JSONRequest(function(data){
rolesObj = data['roles'];
return rolesObj;
}, 'get_roles', params);
}
});
Then I call the following but it returns undefined:
var cls = new users();
alert(cls.getUserRoles().length);
ajax requests are asynchronous so you're not going to get a return value from them. You do, however, receive a callback when they complete so you can pass your "return" value into a callback.
Here is an example of your code re-written to use a callback:
this.getUserRoles = function(completionCallback){
var params = {};
var json = new JSONRequest(function(data){
rolesObj = data['roles'];
completionCallback(rolesObj);
return rolesObj;
}, 'get_roles', params);
}
and then using it:
var cls = new users();
cls.getUserRoles(function(roles) {
alert(roles.length);
});
The rolesObj is passed into the callback function once the JSON request completes.
Your getUserRoles function doesn't return anything. It invokes an asynchronous JSON request, and the success callback for that request returns something.
There is no way to make an asynchronous request in a function and have the function synchronously return a value from the request. The request will take an unknown amount of time, and the requesting function will return as soon as the request has been sent. The value won't have arrived back from the server yet.

return value from ajax request to another function

I'm trying to return a value from (transport) to the calling function, but can't seem to get it to work:
function createXMLHttpRequest( w )
{
var urly = '/users/notes/' + w;
var options = {
method:'get'
, onSuccess: function( transport )
{
x = transport.responseText;
return x;
}
, onFailure: function( transport )
{
var response = transport.responseText;
alert( "FAILED "+ response );
}
};
new Ajax.Request( urly, options );
alert( x );
}
var ai = $( 'addItem' );
ai.onclick = function()
{
// -1 indicates new
addnote( -1, null );
}
x always alerts undefined. Unless I assign x to the Ajax.Request e.g. x=new Ajax.Request(urly,options). It then will alert [Object object]. How can I return the value of transport.responseText to the onclick function?
Your Request is not asynchronous:false. So x is alerted before the request is completed and x is set to transport.responseText.
You have to either set the request as synchronous, or alert x in the onSuccess method.
The return value from onSuccess is discarded by Ajax.Request. Don't return anything.
Ajax is asynchronous by nature. You should query the server, then handle the response in a callback. So you should not try to use the server value in the onclick function, but rather in a separate callback (the onSuccess method).
This is just wrong!
When doing ajax calls you should forget to think synchronous, think asynchronous instead!
Send the request to some url and send a callback function that will be executed once request returns some data.
I wrote simple wrapper for GET calls
// AJAX WRAPPER
MYPROJECT = {};
MYPROJECT.Ajax = (function() {
return{
// get data by AJAX call and return as plain text
get:function(url, callback) {
new Ajax.Request(url, {
method: 'get',
onSuccess: function(transport) {
var data = transport.responseText.evalJSON();
callback(data);
}
});
}
}
})();
// USAGE
MYPROJECT.Ajax.get('/ajax_json_echo/?foo=bar',function(data){
alert(data);
$('containerText').innerHTML = data.get_response.foo
});
You can see the code in action here http://jsfiddle.net/wbDhY/1/
(please be patient, the alert box should appear in 2 seconds)

Categories

Resources