In a click event, I invoke a PageMethods request, which contains two callback functions: OnServerValidationSuccess and OnServerValidationFailure. I also try and set create an object called clientResult;
var clientResult = { rc: "", msg: "" };
$('#btnSave').click( function () {
PageMethods.ServerValidateCreateCompany(companyName, domainName, country, OnServerValidationSuccess, OnServerValidationFailure);
alert(clientResult.rc); //this is null!
});
In the OnServerValidationSuccess, the result parameter contains the asynchronous response. And in there I try to assign it to clientResult.
//On Success callback
function OnServerValidationSuccess(result, userContext, methodName) {
clientResult = result;
if (clientResult.msg.length != 0) {
document.getElementById('resMsg').innerHTML = clientResult.msg;
$('#resMsg').addClass('warning');
}
}
I assign the result to local clientResult variable in the callback function. It should contain the fully formed server response, which is sent correctly by the server-side WebMethod.
However, it remains null or empty after PageMethod is called.
What must I do in order to assign the variable set in the callback to a local variable so that I can access it?
You seem to be assigning the value to clientResult correctly, you're just accessing it too early.
You're making an asynchronous/non-blocking call which means that it returns immediately but continues to work in the background. So your JavaScript immediately returns from the call to PageMethods.ServerValidateCreateCompany and moves on to the alert. But your request hasn't had time to complete and your success callback (OnServerValidationSuccess) hasn't even run yet so you get undefined or null.
You should invoke whatever function is going to process the response in the OnServerValidationSuccess function which is where the response will be received. Perhaps something like this (you already seem to doing something with msg, just move your work with rc here as well)
//On Success callback
function OnServerValidationSuccess(result, userContext, methodName) {
clientResult = result;
alert(clientResult.rc); //this will work
process(clientResult); //process the response here
if (clientResult.msg.length != 0) {
document.getElementById('resMsg').innerHTML = clientResult.msg;
$('#resMsg').addClass('warning');
}
}
Related
I am having a problem, or perhaps a lack of understanding, with the jQuery execution order of $.get() function. I want to retrieve some information from a database server to use in the $.ready() function. As you all know, when the get returns, it passes the data to a return handler that does something with the data. In my case I want to assign some values to variables declared inside the ready handler function. But the problem is, the return handler of $.get() does not execute until after ready has exited. I was wondering if (a) am I doing this right/is there a better way or if (b) there was a way around this (that is, force the get return handler to execute immediately or some other fix I'm not aware of). I have a feeling this is some closure thing that I'm not getting about JavaScript.
As per request, I'll post an example of what I mean:
$(function() {
var userID;
$.get(uri, function(returnData) {
var parsedData = JSON.parse(returnData);
userID = parsedData.userID;
});
});
So as you can see, I'm declaring a variable in ready. Then using a get call to the database to retrieve the data needed. Then I parse the JSON that is returned and assign the userID to the variable declared before. I've tested it with a couple alerts. An alert after the get shows userID as undefined but then an alert in get's return handler shows it to be assigned.
$.get() is asynchronous. You have to use a callback to fill your variable and do the computation after the request is complete. Something like:
$(document).ready(function(){
$.get( "yourUrl", function( data, textStatus, jqXHR ) {
var myData = data; // data contains the response content
// perform your processing here...
registerHandlers( myData ); // you can only pass "data" off course...
});
});
// your function to register the handlers as you said you need to.
function registerHandlers( data ) {
// registering handlers...
}
$.get is an ajax request. A in AJAX stand for asynchronous, so script won't wait for this request to finish, but instead will proceed further with your code.
You can either use complete callback or you can use $.ajax and set async to false to perform synchronous request.
The $.get() function executes an async httprequest, so the callback function will be executed whenever this request returns something. You should handle this callback outside of $.ready()
Maybe if you explain exactly what do you want to do, it would be easier to help!
Are you looking for something like:
$(document).ready(function(){
var variable1, variable 2;
$.get('mydata.url', function(data){
variable1 = data.mydata1;
variable2 = data.mydata2;
});
});
If you declare the variables first, then you can set their values within the get call. You can add a function call at the end of the get handler to call a separate function using these values? Without some kind of example, its hard to go into any more detail.
Without seeing the full code, my guess is that you should declare your variable outside $.ready; initialize it in ready for the initial page load; then update it from the get callback handler.
for example
var x = ""; // declaration
$(document).ready(function() { x = "initial value"; });
$.get(...).success(function() { x = "updated from ajax"; });
I have a function which uses getJSON but its not working like I expected.
function balbla(name, param) {
$.getJSON("/blabla.json?name=" + name + "¶m=" + param, function(data) {
return data.bla;
});
}
When I use alert(data.bla) in the getJSON method it works but when I try return data.bla it doesnt. Also when I create a variable and try to write the value of data.bla to it it simply doesnt work!
// I tried this:
function getRouteData(name, param) {
return $.getJSON('/routes_js.json', {route:name, opt: param});
}
function getRoute(name, param) {
getRouteData(name, param).done(function(data) {
return data.route;
});
}
But when I call getRoute("bla", "blub") it still returns undefined.
AJAX is asynchronous. You cannot easily return a value in such a function that depends on the result of the AJAX call. Change your function to accept a callback:
function balbla(name, param, cb) {
$.getJSON('/blabla.json', {name:name, param: param}, function(data) {
cb(data.bla);
});
}
And use it like this:
balbla('foo', 'bar', function(bla) {
// do stuff
});
An even cleaner way would be returning the jqXHR object:
function balbla(name, param) {
return $.getJSON('/blabla.json', {name:name, param: param});
}
When calling it, use the deferred/promise interface of the jqXHR object to attach a success callback:
balbla('foo', 'bar').done(function(data) {
alert(data.bla);
});
Note that using $.ajax() in synchronous mode is not an option you should consider at all. It may hang the browser's UI (or at least the active tab) until the request finished. Besides that, asynchronous callbacks are the way everyone does it.
If you do not like using callback functions, you could use a preprocessor such as tamejs to generate the asynchronous functions automatically.
The function with your return statement:
function(data) {
return data.bla;
}
… is not being called by your code (it is being called deep inside jQuery), so you have no way to put an assignment of the left hand side of the function call.
It is also being called as part of an asynchronous function, so the balbla function will have finished running and returned before it the anonymous one is ever called.
If you want to do something with the response data, do it inside the anonymous callback function.
getJSON is asynchronous, not synchronous. You need to use a callback so your logic needs to be done in two steps. Calling step and the processing step.
Can someone one explain it please?
Why alert 2 pops before alert 1?
Why value of pageCount in alert 1 is different than alert 2?
function naviSet()
{
var pageCount;
if($.ajax({
type: "POST",
url: "http://localhost/mywebsite/wp-content/themes/twentyeleven/more-projects.php",
success:function(data)
{
pageCount = data;
alert(pageCount); //alert 1
return true;
},
error:function()
{
$("#direction").html("Unable to load projects").show();
return false;
}
})) alert(pageCount); //alert 2
}
The alert1 is inside a callback - this function will only be called when the ajax request completes successfully (ie asynchronously).
The pageCount is different for the same reason - the success callback has not been made when alert2 is called.
As most answers mention you make an asynchronous call, but thats not really the reason. So JavaScript is single threaded, only on think can be done per time.
So first you call your function and this function will put on the execution context stack. This function will be executed before any other function that will be added to stack can be executed. In this function you make your ajax call and on success the success function will be put on the execution context stack. So this function could never ever called before naviSet. As alert1 is made in the naviSet function it will be the called first.
And to your second question:
From your function I think you believe, when $.ajax() returns true, your ajax call was succesful and pageCount was set to data. But it isn't. $.ajax doesn't return true but the truethy value $. Its a function that return reference to the main jquery object, so you can chain function calls.
function naviSet()
{
//you create a new var which is undefined
var pageCount;
// return $ which is a truethy in JavaScript, but it does not mean the ajax call was successful
if($.ajax({
type: "POST",
url: "http://localhost/mywebsite/wp-content/themes/twentyeleven/more-projects.php",
success:function(data)
{
// now you in the context of your success function
// and set the value of your variable to data
pageCount = data;
alert(pageCount); //alert 1
return true;
},
error:function()
{
$("#direction").html("Unable to load projects").show();
return false;
}
}))
//here you are still in the context of your naviSet function where pageCount is undefined
alert(pageCount); //alert 2
}
Why alert 2 pops before alert 1?
Alert 1 is fired by the callback function that is fired when a successful HTTP response has been received.
Alert 2 fires as soon as the HTTP request has been sent.
Networks are slow.
Why value of pageCount in alert 1 is different than alert 2?
Because it is changed when the response has been received (just before it is alerted), by the same callback function as mentioned above.
The ajax-function retrieves data from the given url asynchronously. That means that it is doing it in the background, while the rest of your code executes. As soon as it is finished, the function assigned to "success" is called (or "error", if it fails).
The second alert is called first because of this. Like I said, the rest of the code continues execution while the ajax-function is working.
The reason the second alert happens first is because the ajax call is asynchronous. It essentially schedules a web call and returns immediately. Hence the line after it which is the second alert happens directly after.
At some point later in time the web request will complete and call into the success function. Hence the first alert happens at that point
I can't access the attribute of an instantiated class. The attribute is set using an AJAX call.
I am trying to define the class "CurrentUser", and then set the attribute "userId" using AJAX.
Here I define the class CurrentUser, and give it the attribute userID:
function CurrentUser() {
// Do an ajax call to the server and get session data.
$.get("../../build/ajaxes/account/get_user_object_data.php", function(data) {
this.userId = data.userId;
console.log(data.userId); // This will correctly output "1".
}, "JSON");
}
Here I instantiate a CurrentUser named billybob. Notice how I can't output billybob's attribute:
// Instantiate the user.
var billybob = new CurrentUser();
console.log(billybob.userId); // This will incorrectly ouput "undefined".
I've checked the common errors with AJAX:
The AJAX call returns the data correctly as a JSON object. I can read the correct object in Firebug / Network console. The AJAX call also has a status of "200" and "OK".
I can log the AJAX call's data correctly, as seen in the first part of my code where I log data.userId.
Maybe this clears it out:
In your original code:
function CurrentUser() {
// Do an ajax call to the server and get session data.
$.get("../../build/ajaxes/account/get_user_object_data.php", function(data) {
this.userId = data.userId;
console.log(data.userId); // This will correctly output "1".
}, "JSON");
}
You are creating an anonymous function on the fly, that will be later called by jQuery's internals with this
set to an ajax object. So this will be the ajax object inside the anonymous function, not billybob. So when
you do this.userId = ... this means the ajax object which doesn't have a userid property.
jQuery will have no idea where you got your callback function from, so it cannot set the this automagically
for you.
What you must do is to save the billybob (or any CurrentUser instance) reference and use it in the callback like so:
function CurrentUser() {
var self = this;
$.get("../../build/ajaxes/account/get_user_object_data.php", function(data) {
self.userId = data.userId; //self refers to what this refered to earlier. I.E. billybob.
console.log(data.userId, self.userid); // This will correctly output "1".
}, "JSON");
}
Also note that:
var billybob = new CurrentUser();
console.log(billybob.userId);
By the time you call console.log (I.E. instantly after creating billybob), the ajax request hasn't been completed yet so it is undefined.
In constructor, consider doing
var self = this;
and in function
self.userId = data.userId;
this inside function will be different than outside. Although, I don't know JQuery. May be it's supposed to set up closure automatically.
I have global variable fan_coil_ai_bi, and I use that variable to store some data which I get from request, but problem is that len_1 is 1 ( what is ok value in this case ) and len_2 is undefined (what is wrong). How that happen in my function bellow ? How to achieve that len_2 have same value like len_1 ? What is wrong with this code ?
function read_required_fields(fan_coil_id) {
var parameters = {};
parameters['command'] = 'read_required_fields';
parameters['fan_coil_id'] = fan_coil_id;
$.get("php_scripts/network_script.php", parameters, function(data) {
fan_coil_ai_bi=data;
alert('len_1='+fan_coil_ai_bi.length);
}, "json");
alert('len_2='+fan_coil_ai_bi.length);
}
Asynchronous JavaScript and XML is asynchronous.
The get method means "Make an HTTP get request and when it gets a response, do this".
It does not pause execution of the function until the HTTP response arrives.
If you want to do anything with the data, do it in the callback function (or a function you call from it).
$.get("php_scripts/network_script.php", parameters, function(data) {
fan_coil_ai_bi=data;
alert('len_1='+fan_coil_ai_bi.length);
alert('len_2='+fan_coil_ai_bi.length);
}, "json");
You might want to learn about asynchronous code. In your case, what's happening is:
Request is being sent
len_2 is being alerted
Request finished (there is a response), len_1 is being alerted
So when len_2 is being alerted, fan_coil_ai_bi.length has not been defined yet.
There is no possibility to solve this; rather you already have a working solution: move dependencies into the callback.