I have a site that uses money.js to do realtime currency conversion by getting rates from the Open Currency Exchange API. The JSON data object contains a nested 'rates' object which money.js then uses in a callback function to get data.rates and perform the conversion.
Money.js also provides a wrapper that requires base currency and conversion rates are set in the application and stored in its fx.rates object. These settings are then overwritten by the rates from the API call.
The jQuery implementation works, but I want to convert it to plain js. The Fetch API seems to work until the callback function tries to map fx.rates to data.rates, at this point I get an error: TypeError: Cannot read properties of undefined (reading 'rates’) - this is data.rates not fx.rates. Here is a simplified snippet of the two approaches:
import money from 'money';
// Jquery Version
(function( $ ) {
// Declare Default Exchange Rates
var fx = require("money");
fx.rates = {
"EUR" : 1.17,
"USD" : 1.39,
"GBP" : 1,
}
// Init Connect To Open Exchange Rates API
function initOpenExAPI(){
// Load exchange rates data via AJAX:
$.getJSON(
// NB: using Open Exchange Rates here, but you can use any source!
'https://openexchangerates.org/api/latest.json?app_id=XXXXXXXX&base=GBP',
function(data) {
// Check money.js has finished loading:
if ( typeof fx !== "undefined" && fx.rates ) {
fx.rates = data.rates;
fx.base = data.base;
} else {
// If not, apply to fxSetup global:
var fxSetup = {
rates : data.rates,
base : data.base,
}
}
initEuroConversion();
}
);
}
//Init Money.js conversion
function initEuroConversion() {
$('.js-price').each( function( index, element ){
var value = $(this).data('price');
fx(value).from('GBP').to('EUR');
});
}
//Init First Call To Open Exchange API On Ready
$(document).ready(function () {
initOpenExAPI();
});
}( jQuery ) );
/**
* Vanilla JS Version
*/
// Declare Default Exchange Rates
const fx = require('money');
fx.rates = {
"EUR" : 1.15,
"USD" : 1.12,
"GBP" : 1,
};
fx.base = "GBP";
/**
* Init Connect To Open Exchange Rates API
*/
function initOpenExAPI(){
// fetch rates
fetch('https://openexchangerates.org/api/latest.json?app_id=XXXXXXXX&base=GBP')
.then(response => response.json())
.then(json => console.log(json))
.then(function (data) {
// Check money.js has finished loading:
// This is where it fails
if ( typeof fx !== "undefined" && fx.rates ) {
fx.rates = data.rates;
fx.base = data.base;
} else {
// If not, apply to fxSetup global:
const fxSetup = {
rates : data.rates,
base : data.base,
}
}
// The API call was successful!
//console.log(data); returns object
initEuroConversion();
})
.catch(function (err) {
// There was an error
console.log('Something went wrong.', err);
});
}
// Money.js conversion
function initEuroConversion() {
const subTotal = document.querySelectorAll('.js-price');
subTotal.forEach(el => {
const value = el.getAttribute('data-price');
fx(value).from('GBP').to('EUR');
});
}
Trying to understand why the callback function using the fetch API doesn't have access to the fx object? Any help would be great
CodePudding user response:
.then(json => console.log(json)) .then(function (data) { // Check money.js has finished loading: // This is where it fails if ( typeof fx !== "undefined" && fx.rates ) { fx.rates = data.rates;
The callback to the first then
in this part of your code:
- Receives a JavaScript object (that was parsed from some JSON but isn't JSON itself)
- Logs it
- Returns the return value of
console.log
, which isundefined
The second then
receives the return value of the previous then
, which is undefined
, hence your error.
You need each then
in the chain to return the value you want the next one to receive.
.then(latest => {
console.log(latest);
return latest;
})