Can somebody explain to me the ascending order of the alerts, and the item values of the model in the following piece of backbone.js code?
var model = new Ingredient({"item" : "Before",});
alert("1");
alert(model.get('item')); // Before
model.fetch({ success: function() {
alert("3");
alert(model.get('item')); // After
}});
alert("2");
alert(model.get('item')); // Before
I can't seem to figure out how to update the state of the model in the same scope which it was defined. Is that important?
It's possible I'm thinking about this the wrong way, or I don't understand something fundamental about javascript scoping or functions.
Thanks
The success: function() is called asynchronously as it is really just a wrapper around a JQuery AJAX call. In human speak -. The fetch method makes a request to the server for the model data. The fetch method returns immediately and doesn't wait for the http request to complete. When the http request completes ( if successfully ) then the success: function()
callback is called. This will be the last thing that happens.
Related
I'm having some problems with AJAX and the scope of my data. I am new to Javascript and I'm not sure how to fix my problem.
var urlList = new Array();
$.ajax({
url: "http://localhost:3000/url",
success: function(data) {
alert(data.expressions.url); //This shows the correct result
urlList[0] = obj.expressions.dom;
}
});
alert(urlList[0]); //this shows undefined
I need the data that is in urlList[0] so i can use it at a later time. I think it's a scope problem.
Could someone point me in the right direction please?
Thanks
It's not a scope problem, but a timing problem. The ajax method is executed asynchronously. That means that calling it will not cause your program to wait until it is finished. This results in the alert being shown before the request is finished.
To fix this, put the request inside the success function as well. This is the proper place to handle the results of the request.
var urlList = new Array();
$.ajax({
url: "http://localhost:3000/url",
success: function(data) {
alert(data.expressions.url); //This shows the correct result
urlList[0] = obj.expressions.dom;
// This might work now, depending on what `obj.expressions.dom` is. This
// isn't becoming clear from your code. Usually you would use the `data`
// parameter of the success function, which contains the response body of
// the ajax request that has just finished.
alert(urlList[0]);
// of course you can call other functions as well. For instance, you
// could call
urlListChanged();
// ..which you can declare in global scope. This way, you can repond to
// changes from multiple sources, without having to duplicate code.
// It will all work, as long as you use the success handler as the trigger.
}
});
function urlListChanged()
{
alert(urlList[0]);
}
Your problem is one of chronology.
$.ajax fires an asynchronous request, meaning the rest of your code after it will continue to be executed before the request has resolved. Since urlList is populated only once the request resolves, your alert is firing too early.
Change
$.ajax...
to
var req = $.ajax...
and wrap your alert in a success callback:
req.done(function() { alert(urlList[0]); });
...or just move the alert inside your existing success callback.
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 application where there are numerous number of ajax calls to the server.
Now I want to audit the response that comes from the server (This requirement poped up after the ajax code was laid).
So I have a function that would audit the response data, only problem is how can I get the data to be sent to the function which now sits separately.
I don't want to do the laborious work of adding the line of code for calling the function in each ajax call.
Is there easier and general way out. Somehow I could detect when a response come back and then process the response.
Using both traditional javascript method as well as jquery ajax calls in the system. (The app has been getting changes from a long time and has changed hands a lot so the new things get added and the older ones never get removed)
Wrap your ajax calls with a helper function and use it throughout your code.
An (untested) example:
MyApp = MyApp || {
logRequest: function _logRequest(settings, response) {
// Log your response
},
ajax: function _ajax (settings) {
var that = this;
// Log attempt request here?
// Example of logging the success callback (do similar for error or complete)
if (settings.success) {
// A success handler is already specified
settings.success = function (data) {
that.logRequest(settings, data); // Log the response
settings.success(data); // Call the original complete handler
};
} else {
// No success handler is specified
settings.success = function (data) {
that.logRequest(settings, data);
};
}
return jQuery.ajax(settings);
}
};
I favour this mechanism for lots situations where I want to reduce boilerplate. I only have to modify the state of the MyApp object which is my own (named appropriately for the application), so it is sort of an interface that allows you to intercept function calls without modifying other global objects. You can also swap this functionality out with something else very easily without having to update your references everywhere, which could be useful in a lot of other situations as well.
Using .ajaxComplete() should be enough to catch the onComplete event for all AJAX requests made through jQuery. Isn´t that what you´re asking for?
$('.ajaxRequest').click(function(event) {
event.preventDefault();
$.getJSON(
'/echo/json/',
this.id,
function(data, textStatus, jqXHR) {
console.log(data, textStatus, jqXHR);
}
);
});
// Listen to all ajax requests
$("#log").ajaxComplete(function(event, request, settings) {
console.log(event, request, settings);
});
View demo.
I've written a function which makes an asynchronous request using jQuery.
var Site = {
asyncRequest : function(url, containerId) {
$.ajax({
url : url,
onSuccess: function(data){
$(containerId).html(data);
}
});
}
}
Syntax might be slightly wrong as I'm using notepad, but hopefully you get the idea.
I call the function:
Site.asyncRequest('someurl', container1);
Site.asyncRequest('someurl', container2);
Both requests get sent and processed by the server. Two responses get sent back, which is what I expect. However, I would expect container1 and container2 to contain responses from both requests.
The problem, is that only the last response gets displayed and I can't figure out why. I don't know how the jQuery ajax keeps a track of requests/responses, so maybe this is a problem.
Say I make 5 or 10 requests, how does jQuery ajax know which response is for which request and where does it keep a track of it?
Thank you
This appears to be a Javascript scoping issue. Try the following:
var Site = {
asyncRequest: function(url, containerId) {
(function(theContainer) {
$.ajax({
url: url,
onSuccess: function(data) {
$(theContainer).html(data);
}
});
})(containerId);
}
};
This creates a separate scope for each function call, so the actual value pointed to by "theContainer" is different for each onSuccess anonymous function.
What is happening here is a single closure is getting created, due to the way that function is declared. See "A more advanced example" here: http://skilldrick.co.uk/2010/11/a-brief-introduction-to-closures/
Basically, the containerId is being shared among all instances of that onSuccess anonymous function. I haven't tested this, but I believe if you defined your asyncRequest function outside of Site, this would work.
As far as a more elegant solution to this problem, perhaps someone else will answer better.
It's probably obvious to you, but I can't figure it out.
I need to make function that returns it's inner-function's value. In other words, I have function get_users() that must return JSON object. That JSON object is got by $.post (built-in jQuery).
function get_users() {
return
$.post(
url_base + 'travel/trip/get_users/' + trip_id,
function(response) {
return response;
},
'json'
);
}
(above is what I tried to do, but it returned undefined - what a surprise)
Because of variable scope, I cannot just make variable in inner-function because it won't be visible in main function. I don't want to use global variables neither. Looking for better solution!
Thanks in any advice!
Why are you fighting against the asynchronous nature of AJAX? When you do AJAX you should get accustomed to work with events and callbacks instead of writing sequential code. You can't return the inner contents. The simple reason for this is that this inner function could execute much later than the outer function. So the outer function will return a result much before the success callback executes.
So here's the correct way:
function get_users() {
$.post(
url_base + 'travel/trip/get_users/' + trip_id,
function(response) {
// instead of trying to return anything here
// simply do something with the response
// Depending on what the server sent you there
// will be different ways.
// Here you could also call some other custom function
// and pass it the response
}
'json'
);
}
You can't return values from ajax calls. (Without setting async false, but that wouldn't really be ajax)
By the time you hit the inner return, the outer function has already completed
You will need to use a callback to process the users.
get_users(function(response) { // this anonymous function is passed in as a parameter
// do something with the response
});
function get_users(callback) {
$.post(
url_base + 'travel/trip/get_users/' + trip_id,
function(response) {
// call the passed in function and pass in the response as a parameter
callback(response);
},
json'
);
}
You need a primer on how asynchronous ajax calls work.
When you call $.post(), it starts a networking call to do the post and immediately returns from the $.post() call and continues executing the rest of your javascript. It will even exit your function get_users() right away.
But, the ajax call is not yet done - it's still in progress. Some time later, the ajax call will finish and when that happens the success handler for the ajax call that you have defined as function(response) {...} will get called. Only then, at that later time, is the response value from the ajax call known.
This is what asynchronous ajax means. You cannot write a call like get_users() and expect it to get the users and return with them. Instead, you have to make use of callback functions that will get called some time later (when the ajax has completed) and you can continue the path of your code then. Yes, this is inconvenient, but it's how things work in javascript with asynchronous ajax calls. The benefit of asynchronous ajax calls is that the browser and other javascript code can be fully live while the ajax call is underway. The cost of asynchronous ajax calls is that coding for them is more complicated.
You have a number of choices for how to deal with this complication. First off, you can make your get_users() call and then just continue the programming sequence that you want to carry out in the internal callback inside of get_users() since that's the only place that the response (the actual users) is known. If you're only using get_users() in one place in your code, then that could work fine. It would look like this:
function get_users() {
$.post(
url_base + 'travel/trip/get_users/' + trip_id,
function(response) {
// process the user list here and continue whatever other code you
// need that deals with the user list
},
'json'
);
}
If you need to use get_users() in several different places for different purposes, then you can change it to take a callback itself and let the post call just call that callback when the ajax call is done. You would then complete your processing of the response in that callback function:
function get_users(callback) {
$.post(
url_base + 'travel/trip/get_users/' + trip_id,
callback,
'json'
);
}
In this second option you could call get_users() like this:
get_users(function(response) {
// process the user list here and continue whatever other code you
// need that deals with the user list
});
There are even more advanced options available using jQuery's deferred object.