Building a Currency Converter App with JavaScript
Welcome to another installment of our JavaScript series! In this #90th post, we're diving into a practical and widely applicable project: building a currency converter application. This project will solidify your understanding of DOM manipulation, asynchronous JavaScript, and interacting with external APIs, all crucial skills for modern web development.
A currency converter isn't just a fancy tool; it's a real-world application that helps users understand the value of money across different economies. By the end of this tutorial, you'll have a functional app that fetches real-time exchange rates and performs conversions.
Prerequisites
Before we begin, ensure you have a basic understanding of:
- HTML for structuring web pages.
- CSS for basic styling (though our focus will be JavaScript).
- JavaScript fundamentals: variables, functions, event listeners.
- ES6 features like arrow functions and template literals.
1. Setting Up the HTML Structure
First, let's lay the groundwork with our HTML. We'll need input fields for the amount, dropdowns for selecting source and target currencies, a button to trigger the conversion, and a place to display the result.
<div class="container">
<h2>Currency Converter</h2>
<div class="currency-box">
<div class="input-group">
<input type="number" id="amount" value="1" min="0">
<select id="fromCurrency">
<!-- Currencies will be dynamically loaded here -->
</select>
</div>
<div class="swap-icon">
<button id="swapBtn">⇄</button> <!-- Unicode for swap -->
</div>
<div class="input-group">
<select id="toCurrency">
<!-- Currencies will be dynamically loaded here -->
</select>
</div>
</div>
<button id="convertBtn">Convert</button>
<div class="result" id="result">
<!-- Conversion result will appear here -->
</div>
</div>
A few notes on this structure:
input type="number"for the amount to ensure only numerical input.selectelements with IDsfromCurrencyandtoCurrencyfor our dropdowns.- A
buttonwith IDswapBtnto easily reverse the selected currencies. - An empty
divwith IDresultto display our conversion.
2. Basic Styling (CSS)
While we're focusing on JavaScript, a little CSS will make our app presentable. You can add your own flair, but here's a minimalist example to get you started. (Remember to link your CSS file in your HTML document's <head>, which isn't included in this snippet).
/* Example CSS */
.container {
font-family: Arial, sans-serif;
max-width: 400px;
margin: 50px auto;
padding: 20px;
border: 1px solid #ccc;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
text-align: center;
}
.currency-box {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.input-group {
flex: 1;
display: flex;
flex-direction: column;
margin: 0 5px;
}
#amount, select {
width: 100%;
padding: 10px;
margin-top: 5px;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box; /* Ensures padding doesn't expand width */
}
#swapBtn {
background: #f0f0f0;
border: 1px solid #ccc;
padding: 10px 12px;
border-radius: 50%;
cursor: pointer;
font-size: 1.2em;
margin: 0 10px;
}
#convertBtn {
background-color: #007bff;
color: white;
padding: 12px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 1em;
margin-top: 15px;
}
#convertBtn:hover {
background-color: #0056b3;
}
.result {
margin-top: 20px;
font-size: 1.2em;
font-weight: bold;
color: #333;
}
3. The JavaScript Magic: Fetching Exchange Rates
This is where the real power of JavaScript comes into play. We'll use the ExchangeRate-API (free plan available) for fetching real-time currency exchange rates. You'll need to sign up for a free API key to use it. Once you have it, replace YOUR_API_KEY with your actual key.
3.1. Getting DOM Elements
First, let's grab references to our HTML elements so we can manipulate them with JavaScript.
const amountInput = document.getElementById('amount');
const fromCurrencySelect = document.getElementById('fromCurrency');
const toCurrencySelect = document.getElementById('toCurrency');
const swapButton = document.getElementById('swapBtn');
const convertButton = document.getElementById('convertBtn');
const resultDiv = document.getElementById('result');
const API_KEY = 'YOUR_API_KEY'; // Replace with your actual API key
const API_URL = `https://v6.exchangerate-api.com/v6/${API_KEY}/latest/`; // Base URL for latest rates
3.2. Populating Currency Dropdowns
We need to fetch a list of supported currencies and populate our <select> elements dynamically. The ExchangeRate-API provides an endpoint for this, or you can derive it from the 'latest' rates call.
async function getCurrencies() {
try {
// Fetching rates for a common base like USD will give us all supported currencies
const response = await fetch(`${API_URL}USD`);
const data = await response.json();
if (data.result === 'success') {
const rates = data.conversion_rates;
const currencyCodes = Object.keys(rates).sort(); // Get sorted list of currency codes
currencyCodes.forEach(currency => {
const optionFrom = document.createElement('option');
optionFrom.value = currency;
optionFrom.textContent = currency;
fromCurrencySelect.appendChild(optionFrom);
const optionTo = document.createElement('option');
optionTo.value = currency;
optionTo.textContent = currency;
toCurrencySelect.appendChild(optionTo);
});
// Set default selections
fromCurrencySelect.value = 'USD';
toCurrencySelect.value = 'EUR';
// Now that currencies are loaded, perform initial conversion
convertCurrency();
} else {
resultDiv.textContent = `Error fetching currencies: ${data['error-type']}`;
}
} catch (error) {
resultDiv.textContent = `Network error: ${error.message}`;
console.error('Error fetching currencies:', error);
}
}
We call getCurrencies() once the script loads, and it fetches the list, populates both dropdowns, and sets default values (e.g., USD to EUR).
3.3. Performing the Conversion
Now, let's write the core function that fetches the exchange rate between the selected currencies and performs the calculation.
async function convertCurrency() {
const amount = parseFloat(amountInput.value);
const fromCurrency = fromCurrencySelect.value;
const toCurrency = toCurrencySelect.value;
if (isNaN(amount) || amount < 0) {
resultDiv.textContent = 'Please enter a valid amount.';
return;
}
if (fromCurrency === toCurrency) {
resultDiv.textContent = `${amount} ${fromCurrency} = ${amount} ${toCurrency}`;
return;
}
resultDiv.textContent = 'Converting...'; // Provide user feedback
try {
// Fetch rates for the selected 'from' currency
const response = await fetch(`${API_URL}${fromCurrency}`);
const data = await response.json();
if (data.result === 'success') {
const rates = data.conversion_rates;
const rate = rates[toCurrency]; // Get the rate for the 'to' currency
if (rate) {
const convertedAmount = (amount * rate).toFixed(2); // Round to 2 decimal places
resultDiv.textContent = `${amount} ${fromCurrency} = ${convertedAmount} ${toCurrency}`;
} else {
resultDiv.textContent = `Exchange rate for ${toCurrency} not found.`;
}
} else {
resultDiv.textContent = `Error: ${data['error-type']}`;
}
} catch (error) {
resultDiv.textContent = `Network error: ${error.message}`;
console.error('Error converting currency:', error);
}
}
3.4. Swapping Currencies
The swap button is a nice quality-of-life feature. It simply exchanges the values of the two currency dropdowns.
function swapCurrencies() {
const temp = fromCurrencySelect.value;
fromCurrencySelect.value = toCurrencySelect.value;
toCurrencySelect.value = temp;
convertCurrency(); // Re-run conversion after swapping
}
3.5. Event Listeners
Finally, we need to attach our functions to the appropriate events.
// Load currencies when the page loads
document.addEventListener('DOMContentLoaded', getCurrencies);
// Attach event listener to the convert button
convertButton.addEventListener('click', convertCurrency);
// Attach event listener to the swap button
swapButton.addEventListener('click', swapCurrencies);
// Optional: Convert automatically when amount or currency selection changes
amountInput.addEventListener('input', convertCurrency);
fromCurrencySelect.addEventListener('change', convertCurrency);
toCurrencySelect.addEventListener('change', convertCurrency);
4. Putting It All Together (Your script.js)
Your complete JavaScript file (e.g., script.js) would look like this:
const amountInput = document.getElementById('amount');
const fromCurrencySelect = document.getElementById('fromCurrency');
const toCurrencySelect = document.getElementById('toCurrency');
const swapButton = document.getElementById('swapBtn');
const convertButton = document.getElementById('convertBtn');
const resultDiv = document.getElementById('result');
const API_KEY = 'YOUR_API_KEY'; // <-- IMPORTANT: Replace with your actual API key
const API_URL = `https://v6.exchangerate-api.com/v6/${API_KEY}/latest/`;
// Function to fetch and populate currency dropdowns
async function getCurrencies() {
try {
const response = await fetch(`${API_URL}USD`); // Fetching rates for USD to get all currency codes
const data = await response.json();
if (data.result === 'success') {
const rates = data.conversion_rates;
const currencyCodes = Object.keys(rates).sort();
currencyCodes.forEach(currency => {
const optionFrom = document.createElement('option');
optionFrom.value = currency;
optionFrom.textContent = currency;
fromCurrencySelect.appendChild(optionFrom);
const optionTo = document.createElement('option');
optionTo.value = currency;
optionTo.textContent = currency;
toCurrencySelect.appendChild(optionTo);
});
fromCurrencySelect.value = 'USD'; // Default from currency
toCurrencySelect.value = 'EUR'; // Default to currency
convertCurrency(); // Perform initial conversion
} else {
resultDiv.textContent = `Error fetching currencies: ${data['error-type']}`;
}
} catch (error) {
resultDiv.textContent = `Network error: ${error.message}`;
console.error('Error fetching currencies:', error);
}
}
// Function to convert currencies
async function convertCurrency() {
const amount = parseFloat(amountInput.value);
const fromCurrency = fromCurrencySelect.value;
const toCurrency = toCurrencySelect.value;
if (isNaN(amount) || amount < 0) {
resultDiv.textContent = 'Please enter a valid amount.';
return;
}
if (fromCurrency === toCurrency) {
resultDiv.textContent = `${amount.toFixed(2)} ${fromCurrency} = ${amount.toFixed(2)} ${toCurrency}`;
return;
}
resultDiv.textContent = 'Converting...'; // User feedback
try {
const response = await fetch(`${API_URL}${fromCurrency}`);
const data = await response.json();
if (data.result === 'success') {
const rates = data.conversion_rates;
const rate = rates[toCurrency];
if (rate) {
const convertedAmount = (amount * rate).toFixed(2);
resultDiv.textContent = `${amount.toFixed(2)} ${fromCurrency} = ${convertedAmount} ${toCurrency}`;
} else {
resultDiv.textContent = `Exchange rate for ${toCurrency} not found.`;
}
} else {
resultDiv.textContent = `Error: ${data['error-type']}`;
}
} catch (error) {
resultDiv.textContent = `Network error: ${error.message}`;
console.error('Error converting currency:', error);
}
}
// Function to swap 'from' and 'to' currencies
function swapCurrencies() {
const temp = fromCurrencySelect.value;
fromCurrencySelect.value = toCurrencySelect.value;
toCurrencySelect.value = temp;
convertCurrency(); // Re-run conversion after swapping
}
// Event Listeners
document.addEventListener('DOMContentLoaded', getCurrencies);
convertButton.addEventListener('click', convertCurrency);
swapButton.addEventListener('click', swapCurrencies);
amountInput.addEventListener('input', convertCurrency);
fromCurrencySelect.addEventListener('change', convertCurrency);
toCurrencySelect.addEventListener('change', convertCurrency);
Remember to include your script file in your HTML, typically at the end of the <body> tag, like this:
<!-- ... your HTML content ... -->
<script src="script.js"></script>
Conclusion
Congratulations! You've successfully built a functional currency converter application using HTML, CSS, and JavaScript. This project covers essential front-end development concepts:
- DOM Manipulation: Dynamically adding options to
<select>elements and updating text content. - Asynchronous JavaScript: Using
fetchandasync/awaitto interact with external APIs. - Event Handling: Responding to user interactions like button clicks and input changes.
- API Integration: Retrieving real-time data from a third-party service.
Feel free to experiment with this project further. You could add features like storing favorite currencies in local storage, implementing a chart to show historical rates, or enhancing the UI with more advanced CSS. Keep learning and building!