Lecture 5 - CS50's Web Programming with Python and JavaScript
L5. JavaScript
JavaScript
> We have a client/user that sends an HTTP Request to a server, which sends back an HTTP response. All of the Python code using Django has been running on a server. JavaScript allows us to run code on the client side, meaning no interaction with the server is necessary while it's running, allowing our websites to become much more interactive.
> In order to add some JavaScript to our page, add a pair of <script> tags in our HTML page.
- <script>: To signal to the browser that anything we write in between the two tags is JavaScript code we wish to execute when a user visits the site.
alert('Hello, world!');
- The 'alert' function in JavaScript displays a message to the user which they can then dismiss.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hello</title>
<script>
alert('Hello, world!');
</script>
</head>
<body>
<h1>Hello!</h1>
</body>
</html>
Events
> Event-Driven Programming: A programming paradigm that centers around the detection of events, and actions that should be taken when an event is detected.
- An event can be almost anything including a button being clicked, the cursor being moved, a response being typed, or a page being loaded. Just about everything a user does to interact with a web page can be thought of as an event.
- Event Listeners: Wait for certain events to occur, and then execute some code.
function hello() {
alert('Hello, world!')
}
- Create an HTML button in our page with an 'onclick' attribute, which gives the browser instructions for what should happen when the button is clicked.
<button onclick="hello()">Click Here</button>
- When the user clicks on this button, run the function hello. There's nothing in between the parentheses, means we're not providing anything as input to the hello function, though if the hello function did take inputs, we could certainly add that in between the parentheses.
- These changes allow us to wait to run parts of our JavaScript code until a certain event occurs.
Variables
JavaScript is a programming language. There are three keywords we can use to assign values in JavaScript.
- var: Used to define a variable globally
var age = 20;
- let: Used to define a variable that is limited in scope to the current block such as a function or loop.
let counter = 1;
- const: Used to define a value that will not change.
const PI = 3.14;
> Ex. counter.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Count</title>
<script>
let counter = 0;
function count() {
counter++;
alert(counter);
}
</script>
</head>
<body>
<h1>Hello!</h1>
<button onclick="count()">Count</button>
</body>
</html>
- let counter = 0;: Let there be a new variable called counter, and initially set the value of counter equal to 0.
function count(): Take the value of counter and add 1 to it. Then display an alert that has whatever the current value of counter happens to be.
querySelector
JavaScript allows us to change elements on the page.
- First, introduce a function 'document.querySelector'. This function searches for and returns elements of the DOM(Document Object Model).
let heading = document.querySelector('h1');
- To manipulate the element we've recently found, we can change its 'innerHTML' property.
heading.innerHTML = `Goodbye!`;
> We can also take advantage of conditions in JavaScript.
- Let's say rather than always changing our header to 'Goodbye!', we wish to toggle back and forth between 'Hello!' and 'Goodbye!.
- Use '===' as a stronger comparison between two items which also checks that the objects are of the same type. We typically want to use '===' whenever possible.
-- '===': Check for the two values are equal and also that their types are the same thing.
-- '==': Check that values are the same, but it allows for a bit of differences in types.
#hello.html
-> We have three separate calls to querySelector, even though only two of them will run on any given instance of the function.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Count</title>
<script>
function hello() {
const header = document.querySelector('h1');
if (header.innerHTML === 'Hello!') {
header.innerHTML = 'Goodbye!';
}
else {
header.innerHTML = 'Hello!';
}
}
</script>
</head>
<body>
<h1>Hello!</h1>
<button onclick="hello()">Click Here</button>
</body>
</html>
- document.querySelector: This give us the ability to look through an HTML page and extract an element out of that page so that we can manipulate that HTML element using JavaScript code.
- If I want to select an h1 element, say 'document.querySelector('h1') to go through the page and find me an h1 element. querySelector is only going to return one element, so if there are multiple, it's going to return the first thing it finds.
= Find me the h1 element that will return <h1>Hello!</h1>. If I want to change that HTML, I can do that by modifying the innerHTML property of the JavaScript element. In order to update a property of anything in JavaScript, generally use the dot notation, where dot accesses a property of some particular object. '.innerHTML' means take that element and access its innerHTML property, some property of that object.
- If the innerHTML is equal to Hello, find the h1 element and update its innerHTML is equal to Goodbye.
- const heading: I'm going to create a variable called heading, setting it equal to the result of document.querySelector('h1') and never again will I change what heading is equal to. I'll never have another line of code that says heading equals something else because it is constant. And JavaScript will enforce that this variable should not change.
DOM Manipulation
Use this idea of DOM manipulation to improve our counter page
<!DOCTYPE html>
<html lang="en">
<head>
<title>Count</title>
<script>
let counter = 0;
function count() {
counter++;
document.querySelector('h1').innerHTML = counter;
}
</script>
</head>
<body>
<h1>0</h1>
<button onclick="count()">Count</button>
</body>
</html>
- Change <h1>Hello</h1> to <h1>0</h1>, some initial value for the counter.
- Rather than display an alert that tells me the value of the counter in an alert, say 'document.querySelector('h1').innerHTML=counter': Find the h1 element, update its innerhTML, set it equal to whatever the value of the variable counter happens to be.
=> If I refresh this page, the value of this h1 initially is 0. And every time I click 'count', the contents of that h1 element will be updated. As well as manipulate the DOM, actually making changes in order to produce the effect that I want to see on this actual page.
> Make this page even more interesting by displaying an alert every time the counter gets to a multiple of ten.
- Add a condition that says that if counter mod 10 and mod just gets the remainder when you divide by 10.
- In this alert, we'll want to format a string to customize the message, which in JavaScript we can do using template literals.
- Template literals require that there are backticks (`) around the entire expression and a $ and curly braces {} any substitutions.
- The dollar sign, and then the double curly braces means plug-in the value of a variable there.
function count() {
counter++;
document.querySelector('h1').innerHTML = counter;
if (counter % 10 === 0) {
alert(`Count is now ${counter}`)
}
}
> Now, let's improve the design of this page.
- First, just as we try to avoid in-line styling with CSS, we want to avoid in-line JavaScript as much as possible.
#counter.html
document.querySelector('button').onclick = count;
- Add a line of script that changes the 'onclick' attribute of a button on the page, and remove the 'onclick' attribute from within the 'button' tag.
- We're not calling the 'count' function by adding parentheses afterward, but instead just naming the function. This specifies that we only wish to call this function when the button is clicked. JavaScript supports functional programming, so functions can be treated as values themselves. When the button is clicked on, only then run the count function, and then get its return value and use that as the value for onclick.
- 'document.querySelector('button') find me the button on the page, then I'm going to access its onclick property and set it equal to 'count'.
- I would like to set the value of the button equal to count, that count is the function that should run when the button is clicked on.
> Uncaught TypeError
- The error message says I'm trying to modify the onclick property of null.
- When JavaScript searched for an element using 'document.querySelector('button'), it didn't find anything.
- Because it takes a small bit of time for the page to load, and JavaScript code ran before the button had been rendered. Browser is running our code from top to bottom, the content of the DOM has not yet loaded.
- To account for this, we can specify that code will run only after the page has loaded using the addEventListener function.
- addEventListener: Takes in two argument
1. An event to listen for (ex: 'click')
2. A function to run when the event is detected (ex: hello)
document.addEventListener('DOMContentLoaded', function() {
// Some code here
});
-- DOMContentLoaded: Going to be fired or triggered when the DOM, the structure of the page, is done loading. When all of the elements on the page are done loading, the DOM content has been loaded, and then if I attach an event listener to it, it'll run whatever code I want to run that should only run after the DOM is fully loaded, after all of the content on the page has been loaded.
-- function(): JavaScript allows me to just directly write a function.
-- {...}: Include the body of the function as the second argument to addEventListener.
> We've used an anonymous function that is never given a name.
- Anonymous function: This has no name, but I'm still passing it into the addEventListener function as an argument because I want to run the code inside of the function once the DOM has done loading.
let counter = 0;
function count() {
counter++;
document.querySelector('h1').innerHTML = counter;
if (counter % 10 === 0) {
alert(`Count is now ${counter}`)
}
}
document.addEventListener('DOMContentLoaded', function() {
document.querySelector('button').onclick = count;
});
- .onclick = count -> .addEventListener('click', count);: When the click event happens, run the count function. But you can equivalently shorthand this and just say '.onclick = count', and that would work well.
> Move our JavaScript into a separate file to improve our design.
1. Write all of your JavaScript code in a separate file ending in '.js', maybe 'index.js'.
2. dd a A'src' attribute to the '<script>' tag that points to this new file.
#counter.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Count</title>
<script src="counter.js"></script>
</head>
<body>
<h1>0</h1>
<button>Count</button>
</body>
</html>
- Reference 'counter.js' and use that JavaScript.
#counter.js
let counter = 0;
function count() {
counter++;
document.querySelector('h1').innerHTML = counter;
if (counter % 10 === 0) {
alert(`Count is now ${counter}`)
}
}
document.addEventListener('DOMContentLoaded', function() {
document.querySelector('button').onclick = count;
});
> Why is it useful to have JavaScript in a separate file
- Visual appeal: Our individual HTML and JavaScript files become more readable
- Access among HTML files: We can have multiple HTML files that all share the same JavaScript
- Collaboration: We can easily have one person work on the JavaScript while another works on HTML.
- Importing: We are able to import JavaScript libraries that other people have already written. For example, Bootstrap has their own JavaScript library you can include to make your site more interactive.
> Create a page where a user can type in their name to get a custom greeting.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hello</title>
<script>
document.addEventListener('DOMContentLoaded', function() {
document.querySelector('form').onsubmit = function() {
const name = document.querySelector('#name').value;
alert(`Hello, ${name}`);
};
});
</script>
</head>
<body>
<form>
<input autofocus id="name" placeholder="Name" type="text">
<input type="submit">
</form>
</body>
</html>
- First, run some JavaScript when the DOM is done loading. 'document.querySelector' gives me the element that is a form. There's only one form on the page. '.onsubmit' is the code when I submit the form. Instead of providing the name of a function, I can also just provide the function itself.
- Then in between those curly braces, specify what code should run when the form is submitted by providing this anonymous function instead, using the anonymous function as the value of the onsubmit property of this form.
- There are multiple different input elements. For typing in the name and for telling me you're giving me a button where I can submit this particular HTML form.
- In CSS, we had the ability to run CSS and just say style all the h1's or we could say style all the things with this particular ID or with this particular class. Use the exact same syntax that CSS uses if I want to apply a particular set of styles to only one element that only has one ID.
-- document.querySelector('tag'), document.querySelector('#id'), document.querySelector('.class')
- We use '#name' inside of 'document.querySelector' to find an element with an 'id' of 'name'. We can use all the same selectors in this function as we could in CSS. What I want is what the user actually typed into that input field. And it turns out that if you have an input field in HTML, I can get access to what the user typed in by accessing its value property.
- We use the 'value' attribute of an input field to find what is currently typed in. Value is a property that refers to what it is the user actually typed in.
- I'm not going to reassign name to something else inside of this function. So I can use a const variable instead and that would be better design to say I have a constant variable called name, which is equal to document.querySelector.
- To display an alert, Hello, in backticks and then using the dollar sign, curly brace syntax. So I've extracted the name from the form.
=> Get me the element whose ID is name and get access to its value. Then display an alert that is going to say hello to that person.
- Create an input field where the user can type in some text. 'id' is a unique identifier such that I can reference and find this particular input field.
- We use the 'autofocus' field in the 'name' input to indicate that the cursor should be set inside that input as soon as the page is loaded.
> We can also change the styling of a page. We use buttons to change the colour of our heading.
- Instead of writing the same code multiple times, there's some better way.
- Create a function that is going to handle changing the colour to whatever the button says the colour should be changed to.
- But one problem is that if I just attach the same event listener to all three of the buttons, it's not going to be clear to me when I click on the button, how does the button know what colour we should change the text to.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Colors</title>
<script>
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('button').forEach(function(button) {
button.onclick = function() {
document.querySelector("#hello").style.color = button.dataset.color;
}
});
});
</script>
</head>
<body>
<h1 id="hello">Hello</h1>
<button data-color="red">Red</button>
<button data-color="blue">Blue</button>
<button data-color="green">Green</button>
</body>
</html>
- I want to run this JavaScript when the DOM is done loading. I'd like to change the colour of a particular HTML element when one of the buttons is clicked. So to do that, give them all IDs.
- We change the style of an element using the 'style.SOMETHING' attribute. I can modify any of the CSS style properties. So I updated the color property and set it equal to --
- We use the 'data-SOMETHING' attribute to assign data to an HTML element. We can later access that data in JavaScript using the element's 'dataset' property.
-- I can specify any name that I want for some information that I would like to store about the HTML element. Here, the information I want to store is, what colour you should change the text to when the button is clicked on.
- We use the 'querySelectorAll' function to get an Node List with all elements that match the query. (similar to a Python list or a JavaScript array)
-- Instead of 'querySelector' returning a single a single element that matches what it looks for, 'querySelectorAll' is going to return an array of all of the elements that matched my particular query.
-- And that will give me back a JavaScript array, the equivalent of a list, that represents all of those buttons.
-- Go into the JavaScript console, write 'document.querySelctor('button').
- The forEach function in JavaScript takes in another function, and applies that function to each element in a list or array.
-- For each button, run this function that is going to take one of the elements in the list(button) as input.
-- When the button is clicked on, then go ahead and run a function that is going to 'document.querySelector'. Get me the element whose ID is #hello, change its style. I have access to the button. And I'm currently trying to add an event listener for. In order to access its data properties, I can access a special property of an HTML element called it's dataset property. I can say 'button.dataset.color' to get at the data-color attribute.
= When the DOM content is loaded, meaning all of the content of the page is done loading, I'm going to 'document.querySelectorAll', looking for all of the buttons. For each of those buttons, run a function that takes the button as input. The function adds an onclick handler to the button. When the button is clicked on, get me the #hello element, change its colour to button.dataset.color. This accesses its data-set, all of its data properties, and specifically accesses the colour data property.
JavaScript Console
> Console: For testing out small bits of code and debugging.
- Yon can write and run JavaScript code in the console, which can be found by inspecting element in your web browser and then clicking 'console'.
- One useful tool for debugging is printing to the console, which you can do using the 'console.log' function.
#colors.html - Add this line
console.log(document.querySelectorAll('button'));
Arrow Functions
Arrow Function: Be used where we have an input (or parentheses when there's no input) followed by '=>' followed by some code to be run.
- If a function (function()) takes no input, you can use arrow notation with just parentheses, arrow, block.
- Whatever it is to the left of the arrow sign is the input to the function and whatever it is to the right of the arrow is what code should actually run when the function body gets executed, when the function is called upon.
> We can alter our script above to use an anonymous arrow function.
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('button').forEach(button => {
button.onclick = () => {
document.querySelector("#hello").style.color = button.dataset.color;
}
});
});
- We can also have named functions that use arrows.
#Rewriting of the 'count' function
count = () => {
counter++;
document.querySelector('h1').innerHTML = counter;
if (counter % 10 === 0) {
alert(`Count is now ${counter}`)
}
}
> How to implement our colour switcher using a dropdown menu instead of three separate buttons.
- We can detect changes in a select element using the onchange attribute.
- In JavaScript, this is a keyword that changes based on the context in which it's used.
- In the case of an event handler, this refers to the object that triggered the event.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Colors</title>
<script>
document.addEventListener('DOMContentLoaded', function() {
document.querySelector('select').onchange = function() {
document.querySelector('#hello').style.color = this.value;
}
});
</script>
</head>
<body>
<h1 id="hello">Hello</h1>
<select>
<option value="black">Black</option>
<option value="red">Red</option>
<option value="blue">Blue</option>
<option value="green">Green</option>
</select>
</body>
</html>
- The value is what we'll get in JavaScript when we try and extract the value of a particular select dropdown.
- In between the option tags, what the user is going to see on the page when they actually view it.
- Instead of having any buttons, now I have a select dropdown.
- There's a event called onchange, which applies to things like select dropdown, when something changes in the select dropdown, when a user chooses something different, I can run some code.'
- Get me the hello HTML element, and change its style, color.
- this: A special keyword that always refers to the thing that received the event.
- If I wanted to get the value of that dropdown menu, what it is the user actually selected, say 'this.value' to mean get at the value, the thing that the user selected in that menu.
> Events that we can detect in JavaScript
- onclick
- onmouseover: Detect when you mouse over something, when you're hovering over a particular element.
- onkeydown: When you press down on the key
- onkeyup: When you lift your finger off the key
- onload
- onblur
...
TODO List
<!DOCTYPE html>
<html lang="en">
<head>
<title>Tasks</title>
<script src="tasks.js"></script>
</head>
<body>
<h1>Tasks</h1>
<ul id="tasks"></ul>
<form>
<input id="task" placeholder = "New Task" type="text">
<input id="submit" type="submit">
</form>
</body>
</html>
> Here's the code which we can keep in 'tasks.js'
- We only query for the submit button and input task field once in the beginning and store those two values in the variables submit and 'newTask'.
- We can enable/disable a button by setting its disabled attribute to false/true.
- In JavaScript, we use '.length' to find the length of objects such as strings and arrays.
- At the end of the script, we can add the line return false. This prevents the default submission of the form which involves either reloading the current page or redirecting to a new one.
- In JavaScript, we can create HTML elements using the createElement function. Then we can add those elemtents to the DOM using the append function.
// Wait for page to load
document.addEventListener('DOMContentLoaded', function() {
// Select the submit button and input to be used later
const submit = document.querySelector('#submit');
const newTask = document.querySelector('#task');
// Disable submit button by default:
submit.disabled = true;
// Listen for input to be typed into the input field
newTask.onkeyup = () => {
if (newTask.value.length > 0) {
submit.disabled = false;
}
else {
submit.disabled = true;
}
}
// Listen for submission of form
document.querySelector('form').onsubmit = () => {
// Find the task the user just submitted
const task = newTask.value;
// Create a list item for the new task and add the task to it
const li = document.createElement('li');
li.innerHTML = task;
// Add new element to our unordered list:
document.querySelector('#tasks').append(li);
// Clear out input field:
newTask.value = '';
// Disable the submit button again:
submit.disabled = true;
// Stop form from submitting
return false;
}
});
- Add the usual DOMContentLoaded event listener: I want this JavaSccript to run after the DOM content is loaded.
- document.querySelector('form').onsubmit=()=>{}: I want to run code when the form is submitted.
- const task = document.querySelector('#task').value;: Get me the element with ID #task. '.value' gets the value of the input field, which is what the user actually typed in.
- console.log(task);: Print out what the user typed in to the JavaScript console.
- const li = document.createElement('li'): A function to create a new element, followed by what type of element do I want to create.
- li.innerHTML = task;: The HTML content inside of that list item is going to be task, which is whatever the user typed in.
- document.querySelector('#tasks').append(li): Get me the element whose ID is tasks. If I have an HTML element, I can add a new element inside of it by saying '.append(li)'. Once I have that element, append to the end of what's inside of that element, this value 'li', which happens to be this new element that I've created, a new list item.
- document.querySelector('#task').value='';: If I want to clear out the input field whose ID is task. Get me that input field, change its value equal to the empty string-equal to nothing just to say clear out the value of what happens to be inside of that input field right now.
- <input id="submit"...>, document.querySelector('#submit').disabled=true;: Not allow the user to submit a task if they haven't actually typed something in to the new task field. When I first load the page, I don't want the Submit button to be enabled because I want the user to type in a task first before I enable the Submit button.
- document.querySelector('#task').onkeyup=() => {} : I want to add an event handler for when I type something into the input field.
- document.querySelector('#submit').disabled=false;: Take the same Submit button and set its disabled property equal to false.
- document.querySelector('#submit').disabled = true;: After we've cleared out the value from the input field, get the Submit button and set its disabled property equal to true.
- if (document.querySelector('#task').value.length > 0) ... false; else ... true;: If the length of what the user has typed in is greater than 0, they actually typed something in, give them access to the Submit button. But otherwise, don't give them access to that button.
- return false;: Forms will try and submit when you press the Submit button. Don't submit the form. We're going to do everything client side, everything just inside of the browser.
Intervals
We can set functions to run after a set amount of time.
> Add an interval so even if the user doesn't click anything, the counter increments every second.
- We use the setInterval function, which takes as argument a function to be run, and a time(in milliseconds) between function runs.
#counter.js
let counter = 0;
function count() {
counter++;
document.querySelector('h1').innerHTML = counter;
}
document.addEventListener('DOMContentLoaded', function() {
document.querySelector('button').onclick = count;
setInterval(count, 1000);
});
- setInterval(count, 1000);: Set an interval for count.
- Get rid of 'if...' for simplicity. I want to update the h1 with the new value of the counter and run that count function every 1000 ms(1s).
- If I close the page and go back to it, I've gone back to 0. JavaScript is not saving any state about my page. Every time we're running the page, it's going to go back to 'counter.js'. We're setting the variable counter equal to 0.
Local Storage
// Check if there is already a value in local storage
if (!localStorage.getItem('counter')) {
// If not, set the counter to 0 in local storage
localStorage.setItem('counter', 0);
}
function count() {
// Retrieve counter value from local storage
let counter = localStorage.getItem('counter');
// update counter
counter++;
document.querySelector('h1').innerHTML = counter;
// Store counter in local storage
localStorage.setItem('counter', counter);
}
document.addEventListener('DOMContentLoaded', function() {
// Set heading to the current value inside local storage
document.querySelector('h1').innerHTML = localStorage.getItem('counter');
document.querySelector('button').onclick = count;
});
- Dev's Tool - Application - Local Storage
- I have a value for key counter, whose value in this case happens to be 14.
APIs
JavaScript Objects
> JavaScript Object: Very similar to a Python dictionary, as it allows us to store key-value pairs.
> Create a JavaScript Object representing Harry Potter.
let person = {
first: 'Harry',
last: 'Potter'
};
- Then I can access or change parts of this object using either bracket or dot notation
> One way in which JavaScript Objects are useful is in transferring data from one site to another, particularly when using APIs.
- API(Application Programming Interface): A structured form communication between two different applications.
- For example, we may want our application to get information from Google Maps, Amazon, or some weather service. We can do this by making calls to a service's API, which will return structured data to us, often in JSON(JavaScript Object Notation) form.
- A flight in JSON form:
{
"origin": "New York",
"destination": "London",
"duration": 415
}
- If we wanted our 'airline' to be able to make its data available to other services, so that other web applications or other programs could programmatically access information about 'flights', we could pass data in this format to those other applications so that they could then treat this as a JavaScript object and get access to the information about it.
- Human-readable and machine-readable.
- The value within a JSON don't have to just be strings and numbers. We can also store lists, or even other JavaScript Objects.
{
"origin": {
"city": "New York",
"code": "JFK"
},
"destination": {
"city": "London",
"code": "LHR"
},
"duration": 415
}
Currency Exchange
> To show how to use APIs in our application, let's work on building an application where we can find exchange rates between two currencies.
- We'll use the European Central Bank’s Exchange Rate API.
-- By visiting their website, there's the API's documentation, which is generally a good place to start when you wish to use an API.
- Test this api by visiting the URL: https://api.exchangeratesapi.io/latest?base=USD.
-- In this page, there is the exchange rate between the U.S.Dollar and many other currencies, written in JSON form.
- you can also change the GET parameter in the URL from 'USD' to any other currency code to change the rates you get.
- Instead of the API above, I'll use open.er-api.com/v6/latest/USD.
#currency.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Currency Exchange</title>
<script src="currency.js"></script>
</head>
<body></body>
</html>
> AJAX(Asynchronous JavaScript And XML): Allows us to access information from external pages even after our page has loaded.
- fetch function: Allows us to send an HTTP request. Returns a promise.
-- We can think of promise as a value that will come through at some point, but not necessarily right away.
-- We deal with promises by giving them a '.then' attribute describing what should be done when we get a 'response'.
document.addEventListener('DOMContentLoaded', function() {
// Send a GET request to the URL
fetch('https://api.exchangeratesapi.io/latest?base=USD')
// Put response into json form
.then(response => response.json())
.then(data => {
// Log data to the console
console.log(data);
});
});
- fetch('...'): Fetch from this URL. Make a HTTP request asking for additional information from this URL and get back what the results are going to be.
- .then(...): After I fetch, what should I do when the promise comes back. When I get back the response, what I want to do is convert the response into JSON. Treat it as JSON data, as something that I can then manipulate.
=> Get me the eschange rates, convert the exchange rates data into JSON, and then print out that data.
- The argument of '.then' is always a function.
- Although it seems we are creating the variables 'response' and the 'data', those variables are just the parameters of two anonymous functions.
> Rather than simply logging this data, we can use JavaScript to display a message to the screen
document.addEventListener('DOMContentLoaded', function() {
// Send a GET request to the URL
fetch('https://api.exchangeratesapi.io/latest?base=USD')
// Put response into json form
.then(response => response.json())
.then(data => {
// Get rate from data
const rate = data.rates.EUR;
// Display message on the screen
document.querySelector('body').innerHTML = `1 USD is equal to ${rate.toFixed(3)} EUR.`;
});
});
- I can access the EUR property to get the exchange rate of one US dollar is equal to some number of euros.
- const rate = data.rates.KRW;: Inside of the rates key, and then inside of the EUR key. Get me all the data that came back, access the rates key, and then access the euro key.
-> I'll get the KRW key instead of the EUR key.
- document.querySelector('body').innerHTML:Take that rate, put it inside of the body.
- `1 USD is equal to ${rate.toFixed(3)} KRW.`;: I'd like to take this exchange rate and just round it to three decimal places.
> Now, make the site a bit more interactive by allowing the user to choose which currency they would like to see.
- We'll start by altering our HTML to allow the user to input a currency
<!DOCTYPE html>
<html lang="en">
<head>
<title>Currency Exchange</title>
<script src="currency.js"></script>
</head>
<body>
<form>
<input id="currency" placeholder="Currency" type="text">
<input type="submit" value="Convert">
</form>
<div id="result"></div>
</body>
</html>
> Make some changes to our JavaScript so it only changes when the form is submitted, and so it takes into account the user's input. Add some error checking.
document.addEventListener('DOMContentLoaded', function() {
document.querySelector('form').onsubmit = function() {
// Send a GET request to the URL
fetch('https://api.exchangeratesapi.io/latest?base=USD')
// Put response into json form
.then(response => response.json())
.then(data => {
// Get currency from user input and convert to upper case
const currency = document.querySelector('#currency').value.toUpperCase();
// Get rate from data
const rate = data.rates[currency];
// Check if currency is valid:
if (rate !== undefined) {
// Display exchange on the screen
document.querySelector('#result').innerHTML = `1 USD is equal to ${rate.toFixed(3)} ${currency}.`;
}
else {
// Display error on the screen
document.querySelector('#result').innerHTML = 'Invalid Currency.';
}
})
// Catch any errors and log them to the console
.catch(error => {
console.log('Error:', error);
});
// Prevent default submission
return false;
}
});
- document.querySelector('form').onsubmit = function() {:
- return false;: I just want to run everything locally on this same page
=> I'm going to fetch data from the exchange rates API, convert that data to JSON. Then get access to that data.
- const currency = document.querySelector('#currency').value; : I want to figure out what the user actually typed in to the input field. Get the element whose ID is currency and get its value.
- const rate = data.rates[currency]; : Access a property of rates that is called currency. [square brackets] allows me to use a variable which I defined up as the currency that the user typed in.
- if (rate !== undefined){...}: If the rate is not undefined, update the result.
- else {...} : Otherwise, let the user know that the currency they tried to provide is not actually a valid currency.
- const currency = document.querySelector('#currency').value.toUpperCase();: Takes a string and converts it to uppercase.
댓글 없음:
댓글 쓰기