js variable scope question - javascript

how do i make data overwrite results variable ?
var ajax = {
get : {
venues : function(search){
var results = "#";
$.getJSON("http://x.com/some.php?term="+search+"&callback=?",function(data){ results = data; });
return results;
}
}
};

data is overwriting results, just after results has been returned.
You can use the ajax function instead of getJSON, since getJSON is just shorthand for
$.ajax({
url: url,
dataType: 'json',
data: data,
success: callback
});
and then also set async to false, so that the call will block.
However, in your case this won't work, because JSONP requests (with "?callback=?") cannot be synchronous.
The other (better) option is to have whatever code is dependent on the results return value get called by the success callback.
So, instead of something like this:
var results = ajax.get.venues('search');
$('#results').html(translateResults(results));
Maybe something like this:
ajax.get.venues('search', function (results) {
$('#results').html(translateResults(results));
});
venues = function (search, callback) {
$.getJSON("http://x.com/some.php?term="+search+"&callback=?",
function(data){
callback(data);
});
};

Your problem is the asynchronous nature of JavaScript. results does get overwritten, but only later, after the function has already exited, because the callback is executed when the request has finished.
You would have to make the Ajax call synchronous using sync: true (this is usually not a good idea, just mentioning it for completeness's sake) or restructure your code flow so it doesn't depend on the return value any more, but everything you need to do gets done in the callback function.

This isn't a scope problem. It's because $.getJSON is asynchronous; results is returned before $.getJSON finishes. Try making a callback for $.getJSON to call when it's done.
function JSON_handler(data){
// do stuff...
}
$.getJSON("http://x.com/some.php?term="+search+"&callback=?", JSON_handler);

You could put the logic you want to run in a callback.
var ajax = {
get : {
venues : function(search, fnCallback){
var results = "#";
$.getJSON("http://x.com/some.php?term="+search+"&callback=?",
function(data){
// success
results = data;
(typeof fnCallback == 'function') && fnCallback(data);
});
return results;
}
}
};
ajax.get.venues(term, function(result){
// Do stuff with data here :)
})
functional programming can be fun.

Related

function reading JSON data not passing to variables

I am creating a function to read different JSON files. The problem is when I try to pass the array.
I keep getting 'undefined' once I am back to my primary function.
Reading the file works but when I try to use the variable I get 'undefined'.
I could use some help. thanks.
This is the file I read 'data.json':
[
{
"code":"10000",
"name":"new",
"filter":"Office",
"label":"NEW"
},
{
"code":"10001",
"name":"classic",
"filter":"Office",
"label":"CLASSIC"
},
{
"code":"10002",
"name":"old",
"filter":"Office",
"label":"OLD"
}
]
Here's my code:
function readfile(myfile) {
var mydata;
$.get(myfile, function (data) {
mydata = JSON.parse(data);
console.log(mydata); // result ok
});
console.log(mydata); // undefined
return (mydata); // return 'undefined'
}
var content = readfile('data.json'); //should be an array
console.log(content); // undefined
You're almost there!
The jQuery $.get() method is an asynchronous call. That means that instead of making the request to get myfile, waiting until it is complete, and then continuing from there, the code will make the request and continue on while the request is done in the background.
There are two things you can do here.
The first thing you can do is simply move your logic inside the callback function like so
$.get(myfile, function (data) {
mydata = JSON.parse(data);
console.log(mydata); // do whatever you need
});
However, if you want to continue using the readfile method, you can make the $.get request synchronous, wait for the response, then return from it.
Like so:
function readfile(myfile) {
var mydata;
$.get({
url: myfile,
async: false,
success: function(data) {
mydata = data;
}
});
return mydata;
}
Get is asynchronous meaning that it will not execute in the order it is written.
$.get(myfile, function (data) {
mydata = JSON.parse(data);
console.log(mydata); // result ok
});
This is why
console.log(mydata); // undefined
return (mydata);
is undefined, because the values are not actually set from get().

jQuery When Done on dynamically pulled function call

I have the following code:
In site-code.js
....
var ajaxContentFunc = $(origin).data("modal-content-handler");
$.when(window[ajaxContentFunc]()).done(function (resp) {
kModal.showContent(resp);
});
In another file I have the following tag and function
Click Me
....
function ajaxContentGeneration() {
var aProm = $.ajax({
url: "tests/ajax/AjaxTest.aspx",
data: { exampleType: "modal-ajax" },
dataType: "html"
});
aProm.done(function (data) {
console.log("Ajax Loaded!");
var content = $(data).find("#ajax-content");
return aProm;
});
}
I need to populate the result of the ajaxContentGeneration (whatever method that might be) into the variable to send to showContent or in other words:
1) Pull the ajaxContentFunction Name from the tag's modal-content-handler data attribute
2) Call function (in this case ajaxContentGeneration)
3) Wait for the function's ajax to complete and return the data generated (in this case html)
4) When completed pass that value to kModal.showContent(----Here----);
However currently I am getting:
1) Pulls ajaxContentFunctionName correctly
2) Calls Function (ajaxContentGeneration() function)
3) Calls kModal.showContent(undefined). This is called prematurely because the deferred isn't correctly waiting for the function call to complete (after the ajax is done).
4) Ajax Completes
Where am I messing up here ?
As far as I can tell, you are 95% there.
Use .then() instead of .done() and return the promise returned by $.ajax().then() :
function ajaxContentGeneration() {
return $.ajax({
url: "tests/ajax/AjaxTest.aspx",
data: { exampleType: "modal-ajax" },
dataType: "html"
}).then(function (data) {
return $(data).find("#ajax-content"); // this will return jQuery
// return $(data).find("#ajax-content").html(); // this will return html
});
}
You can probably also purge $.when() from the top-level call :
var ajaxContentFunc = $(origin).data("modal-content-handler");
window[ajaxContentFunc]().then(function (resp) {
// `resp` is whatever was returned by the `return $(data).find()...` statement above
kModal.showContent(resp);
});
The reason I say "probably" is that $.when() would be necessary if value-returning (not promise-returning) functions could be called instead of ajaxContentGeneration().
Another way would be to do:
// should really be renamed...
function ajaxContentGeneration(){
return $.ajax({
url : "tests/ajax/AjaxTest.aspx",
data : { exampleType: "modal-ajax" },
dataType : "html"
})
}
Somewhere else:
var ajaxContentFunc = $(origin).data("modal-content-handler");
window[ajaxContentFunc]()
.done(function(RES){
kModal.showContent( $(RES).find("#ajax-content") );
});
So the functionality of the ajaxContentGeneration function will be to return an AJAX promise, and not have it manipulated inside it, but do the manipulation where needed (getting the #ajax-content element from the response)
Note that this whole thing is bad practice JS design, and you should avoid having functions on top of the window object, but instead on another object.

Stopping Code until AJAX call completes inside $.each loop

I have a function that loads HTML from an external file via an AJAX call using jQuery.
These ajax call runs inside of a $.each loop and I need this ajax call to finish before the loop continues. Here is my code:
$('img').each(function(){
var cotainer_html = $('.cotainer_html').clone();
/* Get Image Content */
$.ajax({
url: '/assets/ajax/get_studio_image.php',
type:'GET',
success:function(data){
cotainer_html.find('.replaceme').replaceWith(data);
}
});
});
I know I can set async:false but I hear that is not a good idea. Any ideas?
To achieve this you can put each request in to an array and apply() that array to $.when. Try this:
var requests = [];
$('img').each(function(){
var cotainer_html = $('.cotainer_html').clone();
/* Get Image Content */
requests.push($.ajax({
url: '/assets/ajax/get_studio_image.php',
type:'GET',
success:function(data){
cotainer_html.find('.replaceme').replaceWith(data);
}
}));
});
$.when.apply($, requests).done(function() {
console.log('all requests complete');
});
Note that you're replacing the same content on each request, so the only one which will have any effect on the UI is the last request. The preceding ones are redundant.
Also note that you should never, ever use async: false. It locks the UI thread of the browser until the request completes, which makes it look like it has crashed to the user. It is terrible practice. Use callbacks.
The OP appears to want the calls to run in series, not in parallel
If this is the case you could use recursion:
function makeRequest($els, index) {
var cotainer_html = $('.cotainer_html').clone();
$.ajax({
url: '/assets/ajax/get_studio_image.php',
type:'GET',
success:function(data){
cotainer_html.find('.replaceme').replaceWith(data);
if ($els.eq(index + 1).length) {
makeRequest($els, ++index);
} else {
console.log('all requests complete');
}
}
});
}
makeRequest($('img'), 0);
You can use a pseudo-recursive loop:
var imgs = $('img').get();
var done = (function loop() {
var img = imgs.shift();
if (img) {
var cotainer_html = $('.cotainer_html').clone();
/* Get Image Content */
return $.get('/assets/ajax/get_studio_image.php')
.then(function(data) {
cotainer_html.find('.replaceme').replaceWith(data);
}).then(loop);
} else {
return $.Deferred().resolve(); // resolved when the loop terminates
}
})();
This will take each element of the list, get the required image, and .then() start over until there's nothing left.
The immediately invoked function expression itself returns a Promise, so you can chain a .then() call to that that'll be invoked once the loop has completed:
done.then(function() {
// continue your execution here
...
});

Javascript: is there a better way to execute a function after x amount of async database/ajax calls

using Backbone.js we have an application, in which on a certain occasion we need to send an ajax post to a clients webservice.
however, the content to be posted, is dynamic, and is decided by a certain array.
for each item in the array we need to go fetch a piece of data.
after assembling the data that aggregated object needs to be sent.
as of now, i have a synchronous approach, though i feel that this is not the best way.
var arrParams = [{id: 1, processed: false},{id: 7, processed: false},{id: 4, processed: false}];
function callback(data) {
$.post()... // jquery ajax to post the data... }
function fetchData(arr, data, callback) {
var currentId = _(arr).find(function(p){ return p.processed === false; }).id; // getting the ID of the first param that has processed on false...
// ajax call fetching the results for that parameter.
$.ajax({
url: 'http://mysuperwebservice.com',
type: 'GET',
dataType: 'json',
data: {id: currentId},
success: function(serviceData) {
data[currentId] = serviceData; // insert it into the data
_(arr).find(function(p){ return p.id === currentId; }).processed = true; // set this param in the array to 'being processed'.
// if more params not processed, call this function again, else continue to callback
if(_(arr).any(function(p){ return p.processed === false }))
{
fetchData(arr, data, callback);
}
else
{
callback(data);
}
},
error: function(){ /* not important fr now, ... */ }
});
}
fetchData(arrParams, {}, callback);
isn't there a way to launch these calls asynchronous and execute the callback only when all results are in?
You have to use JQuery $.Deferred object to sync them. Look at this article Deferred Docs
You can use in this way:
$.when(
$.ajax({ url : 'url1' }),
$.ajax({ url : 'url2' }) // or even more calls
).done(done_callback).fail(fail_callback);
I would do something like this:
make a function that besides the parameters that you pass to fetchData also gets the index within arrParams, then in a loop call that function for every element. In the success function set processed in your element to true, and check if "you're the last" by going through the array and see if all the rest is true as well.
A bit of optimization can be if you make a counter:
var todo = arrParams.length;
and in the success you do:
if (--todo == 0) {
callback(...)
}

Jquery get text file and return the value to other function

Can any one help me what im wrong in
function separateerror()
{
var jqxhr = $.get("/errormsg.txt", function(data) {
line = data;
array = line.split(',');
getmsg=array[0];
})
return getmsg;
}
i need to return "getmsg" to another function, but its not working, where as if i add alert inbetween
function separateerror()
{
var jqxhr = $.get("/errormsg.txt", function(data) {
line = data;
array = line.split(',');
getmsg=array[0];
})
//alert(getmsg)
return getmsg;
}
the value returns, what wrong im doing in code?
$.get is an async call and what happens is that if you add an alert in between, you give time for the async call to finish and then your value is already set by the time the separateerror function finishes. Otherwise, the separateerror function returns before the $.get call finishes and then your getmsg is probably still a null value.
While working with async calls you should not use this simple model of calling functions and expecting theirs values in return, you should use callback functions to accomplish that the right way.
EDIT:
Also, you should handle the $.get error callback, in case something happens and you can not load the txt file.
function separateerror()
{
var jqxhr = $.get("/errormsg.txt", function(data) {
line = data;
array = line.split(',');
getmsg=array[0];
dosomething(getmsg);
})
.error(function() { alert("error"); });
}
function dosomething(msg) { ... }
Insert that to the top of your script. That /should/ fix it.
$.ajaxSetup({
async: false
});

Categories

Resources