The purpose of the following functions are to access a script on Yahoo's servers and lookup a live currency conversion rate which will later be used to process a customer's purchases.
I'm able to access the rates in the JavaScript alert but I can't seem to return them to the Jquery method which originally called the getRate()
function.
I've tried a standard return rate;
at the end of the parseExchangeRate()
function, which doesn't work. I've also tried setting rate
as a global variable within parseExchangeRate()
but that doesn't work either.
function getRate(from, to) {
var script = document.createElement('script');
script.setAttribute('src', "http://query.yahooapis.com/v1/public/yql?q=select%20rate%2Cname%20from%20csv%20where%20url%3D'http%3A%2F%2Fdownload.finance.yahoo.com%2Fd%2Fquotes%3Fs%3D"+from+to+"%253DX%26f%3Dl1n'%20and%20columns%3D'rate%2Cname'&format=json&callback=parseExchangeRate");
document.body.appendChild(script);
}
function parseExchangeRate(data) {
var name = data.query.results.row.name;
rate = parseFloat(data.query.results.row.rate, 10);
alert("Exchange rate " + name + " is " + rate);
}
$(function() {
getRate('USD', 'PHP');
xRatePHP = rate;
/* Do stuff with rate */
});
Firebug informs me the rate
is undefined when I try to access it in Jquery function.
The other thing I tried was setting the last parameter of the http request to callback=rate=parseExchangeRate
which (not surprisingly) didn't work either.
UPDATE
@Relfor solved the original problem, which was that rate
was not properly declared as a global variable in the global scope. I fixed that and then found a further issue which some have also identified below, which is that after getRate()
is called (which can take about 2000ms to update the variable rate
), the script moves on immediately without waiting for rate
to be updated and uses rate regardless of whether it's ready.
I tried was attempting to use window.setInterval
to create a delay to solve this, when it came to my attention that their was still activity in the thread even though I'd already accepted @Relfor's answer, so I'd prefer to bring it back here so that when we have this working, others can benefit from the solutions.
There is one final (I hope - final!) problem and that is that in order simplify the original question for posting, I ommitted to disclose that I'm actually trying to get two rates from Yahoo! (which possibly a few more planned) and therefore, I'm calling getRate()
in a loop as follows:
function getRate(from, to) {
var script = document.createElement('script');
script.setAttribute('src', "http://query.yahooapis.com/v1/public/yql?q=select%20rate%2Cname%20from%20csv%20where%20url%3D'http%3A%2F%2Fdownload.finance.yahoo.com%2Fd%2Fquotes%3Fs%3D"+from+to+"%253DX%26f%3Dl1n'%20and%20columns%3D'rate%2Cname'&format=json&callback=parseExchangeRate");
document.body.appendChild(script);
}
function parseExchangeRate(data) {
var name = data.query.results.row.name;
rate = parseFloat(data.query.results.row.rate, 10);
}
var rate = 1.00;
var timer;
var q;
var xRatePHP, xRateGBP;
$(function() {
function getTheRates() {
var rateArr = new Array('PHP','GBP');
for (var x=0; x < rateArr.length; x++) {
getRate('USD', rateArr[x]);
q = 0;
timer = window.setInterval(function(){manageTimer(rateArr[x])},100);
}
}
function manageTimer(c) {
if (rate != 1) {
window.clearInterval(timer);
/* Note that 'c' is undefined according to 'alert' below,
* so this next line is not working correctly.
*/
eval("xRate"+c+" = rate;");
alert(c + " = " + rate); // displays 'undefined 43.543'
rate = 1.00;
}
q++;
if (q > 30 ) {
window.clearInterval(timer);
// added below because above isn't working (but neither does this!)
timer = '';
alert(c+' timeout'); // 'c' is undefined according to alert ???
q = 0;
}
}
getTheRates();
/* Do stuff with the rates */
});
It was suggested that I move /* Do stuff with the rates */
to inside the function parseExchangeRate()
but not sure whether that advice would still stand given my revelations about calling getRate()
in a loop?
UPDATE 3 (replaced update 2)
I have created a JSbin here: http://jsbin.com/udikas/3/edit with the above which apart from these two issues appears to be working:
1) The timeout mechanism appears not to be working.
2) On line 33 this line alert('start timer (' + x +')');
without which, the timer doesn't seem to start! I have no idea why, but I can't leave that line in.
the variable rate
has not been defined
$(function() {
getRate('USD', 'PHP');
xRatePHP = rate;
/* Do stuff with rate */
});
after studying your code it seems that rate is defined in the parseExchange(data)
function as
function parseExchangeRate(data) {
var name = data.query.results.row.name;
rate = parseFloat(data.query.results.row.rate, 10);
alert("Exchange rate " + name + " is " + rate);
}
if you want rate to be accessible from the function namespaces without declaring them from within then the rates would have to specified in the global namespace, which is outside any of the functions or loops.
Edit : The namespace problem has been solved and the answer I've given has been accepted, however I would like to add details about the code you are handling here. It has been taken from the gist here: https://gist.github.com/henrik/265014
the reason why parseExchangeRate
exists and the context of it can seem mysterious at first glance, albeit its existence is the primary connection between your JSONP request and the data returned by the response.
If you take a closer look at the request:
http://query.yahooapis.com/v1/public/yql?
q=select%20rate%2Cname%20from%20csv%20where%20url%3D'http%3A%2F%2F
download.finance.yahoo.com%2Fd%2F
quotes%3Fs%3DUSDPHP%253DX%26f%3Dl1n'%20and%20
columns%3D'rate%2Cname'&format=json&callback=parseExchangeRate
(I broke the link up into many lines to make it easier to read)
Carefully look at the last segment of the url: callback=parseExchangeRate
This here is the connection, when the JSONP request is complete parseExchangeRate will be called.
Let me display the code once again:
$(function() {
getRate('USD', 'PHP');
xRatePHP = rate;
/* Do stuff with rate */
});
We should break this up:
getRate('USD', 'PHP')
does the job of loading the JSONP with the respective currency types of 'USD' and 'PHP' xRatePHP = rate
assigns the right hand side which is rate
to xRatePHP
. But this line gave us a problem! our console pal told us that rate
is undefined! The truth: mr.console did not lie, rate
is actually undefined, however mr.console without any further commands given by you a few moments later if asked again would reply that rate
is actually defined. Is this magic?
What is actually happening is that between the time you go from this line
getRate('USD', 'PHP');
to
xRatePHP = rate;
the JSONP response from mr.yahoo hasn't yet come back, which is why when xRatePHP = rate
is issued rate
seems to be undefined.
Hard Code Solution
Let us hard code a duration for our code to wait before using rate
so that we know that mr.yahoo responded, setTimeout
will helps us here:
getRate('USD', 'PHP');
setTimeout(function(){alert(rate)}, 2000);
and everything works now! check the demo at: http://jsbin.com/udikas/1/edit
Soft Code
did you ever consider the case where mr.yahoo takes more than 2000 ms to respond? or maybe even lesser than that? (yahoo is pretty fast!) let us instead take a different approach, this will let us use rate
the exact moment we calculate it with parseExchangeRate
for this we will have to add a callback from parseExchangeRate
:
function parseExchangeRate(data) {
var name = data.query.results.row.name;
rate = parseFloat(data.query.results.row.rate, 10);
alert("Exchange rate " + name + " is " + rate);
}
to
function parseExchangeRate(data) {
var name = data.query.results.row.name;
rate = parseFloat(data.query.results.row.rate, 10);
alert("Exchange rate " + name + " is " + rate);
gotTheRate(rate)
}
and then change
$(function() {
getRate('USD', 'PHP');
alert(rate)
});
to
function gotTheRate(rate){
alert(rate);
}
$(function() {
getRate('USD', 'PHP');
});
a demo of this can be found at http://jsbin.com/udikas/2/edit
Remember hard coding setTimeouts
isn't fun, so let us remove that, manageTimer
, q
, and other such elements from your code, instead we can have:
function getRate(from, to) {
var script = document.createElement('script');
script.setAttribute('src', "http://query.yahooapis.com/v1/public/yql?q=select%20rate%2Cname%20from%20csv%20where%20url%3D'http%3A%2F%2Fdownload.finance.yahoo.com%2Fd%2Fquotes%3Fs%3D"+from+to+"%253DX%26f%3Dl1n'%20and%20columns%3D'rate%2Cname'&format=json&callback=parseExchangeRate");
document.body.appendChild(script);
}
function parseExchangeRate(data) {
var name = data.query.results.row.name;
rateDict[name.match(/USD to ([\w]*)/)[1]] = parseFloat(data.query.results.row.rate, 10);
total_responses++;
if (total_responses === rateArr.length){
for (var k in rateDict){
alert("USD to " + k + " is " + rateDict[k]);
}
}
}
var rate = 1.00;
var timer;
var q;
var rateArr = new Array('PHP','GBP')
var total_responses = 0;
var rateDict = {};
$(function() {
function getTheRates() {
for (var x=0; x < rateArr.length; x++) {
getRate('USD', rateArr[x]);
}
}
getTheRates();
});
http://jsbin.com/udikas/4/edit
-Relfor
You should re order your code flow:
function getRate(from, to) {
var script = document.createElement('script');
script.setAttribute('src', "http://query.yahooapis.com/v1/public/yql?q=select%20rate%2Cname%20from%20csv%20where%20url%3D'http%3A%2F%2Fdownload.finance.yahoo.com%2Fd%2Fquotes%3Fs%3D"+from+to+"%253DX%26f%3Dl1n'%20and%20columns%3D'rate%2Cname'&format=json&callback=parseExchangeRate");
document.body.appendChild(script);
}
function parseExchangeRate(data) {
var name = data.query.results.row.name;
var rate = parseFloat(data.query.results.row.rate, 10);
alert("Exchange rate " + name + " is " + rate);
xRatePHP = rate;
/* Do stuff with rate */
}
$(function() {
getRate('USD', 'PHP');
// rate is not yet available here, so don't do anything with it
});
try to put:
var rate = 0;
on top of your code. This will fix the error. Then you have to consider that if you get 0 maybe you are reading the variable at the wrong time, before it gets populated.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.