JavaScript - Lecture 5 - CS50's Web Programming with Python and JavaScript 2018

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[MUSIC PLAYING] SPEAKER 1: Welcome back, everyone, to Web Programming with Python and JavaScript. And let's pick up where we last left off. So over the course of the past couple of weeks, we've been working on designing web applications, primarily using Flask. And if we think about web applications in terms of clients and servers-- where the client is the user of the application on their computer who goes to your web address and is interacting with your web application, and your server is where your Flask application code is running-- then you can think about where code is actually running in terms of this diagram. And so so far, when we've been writing Python code in Flask, all of that code has been running on the server. So the user on their computer makes a request for a particular web page. I have either Get, or Post, or some other HTTP method. That request is made to our web server, which is running in Flask with Python. That server tries to process that response, understand what it is that the client is asking for. And then ultimately, that server sends back some HTML and maybe CSS content back to the client, which is rendered in that client's web browser. What we're going to transition to today is looking at code that doesn't run on the server but rather runs instead on the client, on the user's own computer inside of their web browser. Now, what might be some reasons why we would want code that runs on the client as opposed to just on the server like we have been over the course of the past couple weeks? AUDIENCE: [INAUDIBLE] SPEAKER 1: Sure. Certainly. So one possible reason is that if you have a lot of users that are all trying to access your application at the same time, than anything you can do to take some of the load off of the server so that you don't have too many clients all trying to connect to the server simultaneously, that can help to reduce the load on the server. Fantastic. And that would be one reason why we might want code running on the client. Why else might we want code, in some cases, to run on the client instead of on the server? Other thoughts or ideas? Yeah? AUDIENCE: It's faster to [INAUDIBLE] have to go to the server and back. You can just [INAUDIBLE]. SPEAKER 1: It's faster. Sure. So if we want something to happen and that something or computation doesn't need to be something that the server is processing, then we may as well just have the client run that code in the web browser as opposed to the additional latency, the additional time that it would take for the client to make a request to the server, for the server to run the code, and then the server to respond back to the client. And so these are some reasons, as we'll soon see, where it becomes more powerful and more useful to have code that's actually running inside of the web browser. And that's what we're looking at over the course of today. So to do that, we're going to be introducing another language. We spent the last couple of weeks working in Python, but today we're going to introduce JavaScript, which is a language really designed for usage to be run inside of web browsers, although now it's used elsewhere as well. But primarily, we're going to be using JavaScript inside of web browsers to run code on the client, so that we don't need to talk to some external server necessarily for all of the computational work that we need to do. Now, JavaScript has come in a number of different variations and it's been updated over time. And different browsers obey slightly different variations of the language, where some web browsers support some features of JavaScript and others support other features. And so in order to manage all of this complexity of different versions and different features of JavaScript, there are certain standard versions of JavaScript that have been released over the years, such that we can make sure that most modern browsers will be compliant with particular standards. And the version of JavaScript that we're going to be using in this class is one of the more popular, more recent versions of JavaScript known as ES6. And so this is just one particular standard version of JavaScript that pre-defines a certain list of features, some of which are new features that weren't in previous versions of JavaScript. But most web browsers nowadays support this latest version of JavaScript ES6. And so that's going to be the version that we're primarily going to be using in this class. So let's take a look at some actual JavaScript code and what it might look like if we were to run it. And so if we were going to try to put some JavaScript code inside of a web page, it might look something like this. This would be a very simple JavaScript section of a web page. And what you'll notice is that it's enclosed inside of script tags. We saw HTML tags over the course of several weeks prior. And what we're going to be looking at with JavaScript is JavaScript code that is inside of our HTML pages, located, in particular, inside of these script tags. And in this case, what we have appears to be a calling a function. We have a function called alert. And inside the body of this function, we have the phrase "Hello, world!" And so let's take a look at this code actually in action if we were going to try to run this inside of a web page. So I go ahead and open up hello0.html. This is just an HTML document, a web page where we have some web content here. You'll notice that, just like before, we have a head section to the web page, we have a body section to the web page, where all that's inside of it is one big heading that says "Welcome." And inside of these script tags, we have this call to an alert function. And that alert function just has, as its argument, the string "hello!" with an exclamation point. And as you might guess, this alert function is a function that is part of JavaScript. And what it will do is it will display an alert window for us. So if I were to now open hello0.html, what I get is an alert in my web browser that says, this page says "hello," exclamation point. And I would press OK. Now I see the rest of that web page. So that was our very first JavaScript application, or web page. And the way we were able to make that happen was just by including JavaScript code inside of our HTML document, so long as it is enclosed inside of these script tags. And so that was a very simple example of how we might want a JavaScript code to run when it's inside of a web page. What you probably noticed is that I didn't have to do anything other than just open this web page in order for this JavaScript code to run. As soon as I opened the page, it gave me the alert that said "hello," and that was that. What we likely want to do, though, as we begin to develop more sophisticated web pages is make it so that all of the JavaScript code isn't running right all at the beginning all at once. But instead, we want certain JavaScript code only to run or only to execute after certain things happen or when certain events happen, so to speak. And so in order to do that, what we'll do is we'll take a look at events.html. And what you'll notice here is inside of the script tag, just like before, rather than just immediately say, alert hello, where "hello" is the argument that's being passed into this alert function, we're instead defining a function. And so this function is called hello. It takes no arguments. And inside the body of this function, we say, alert('Hello!'). And you notice that JavaScript will use these curly braces to denote things that are contained within the function, unlike Python which used indentation to denote what's inside of the function and what's not. These are just syntactic differences, but the general idea is going to be the same thing, that hello here is a function, some block of code that we can later call on when we want the alert message to appear. But notice inside of the script tag, we never actually have any code that says, run the hello function. We just have these three lines that are defining, this is what the hello function is, but no actual use case in which we are running that hello function yet. But if we look down later in the HTML page, we have this heading that says "Welcome." And we also have this button. And the button says, click here, just defined by button tags with "click here" inside of those tags. But we've given this button an additional attribute-- onclick. And inside of its onclick attribute, we've set it equal to "hello," the JavaScript code that we want to run. We want to run the hello function when this button is clicked. And the way to think about this from a JavaScript perspective is that JavaScript understands some certain events, where click is an event, where if you click on a button, that triggers the click event, so to speak. And when that click event is triggered, when that button is clicked on, when I click on Click Here, what should JavaScript do? Well, in this case, I'm telling the web browser that I want to run the hello function that I've defined up here earlier inside of these script tags. And so the result of this is if I open events.html, no alert message pops up right away. I just see "Welcome!" as the heading. And then I also see this Click Here button down below. And it's only when I click that button that the click event is triggered, which triggers the calling of the hello function inside of my JavaScript. And the result of that is that when I click there, then I get the pop-up window that says, This Page Says Hello. And if I were to click on it multiple times, I would see it again and again. This is equivalent to me calling that function on multiple occasions. So questions about what we've seen so far in terms of JavaScript code, and enclosing things in script tags, and events? Yes. AUDIENCE: Can you go back to the first one? SPEAKER 1: Yup, so this was the original code that we started with. AUDIENCE: Can you put the script after the [INAUDIBLE]?? SPEAKER 1: Good question. So the question is, what would happen if you took these script tags and placed it after "Welcome," just placed it down there, and then tried to open it? In this case, it still says This Page Says Hello before you see it. And this, I think, is just Chrome that is processing the alert message first before it goes on to dealing with the rest of the content of the page. Other questions? Yeah. AUDIENCE: Is that for all JavaScript or just [INAUDIBLE]?? SPEAKER 1: I'll have to get back to you on that, but generally speaking, JavaScript will try to execute top to bottom, though there are certain cases in which it can behave in asynchronous ways. And we'll take a look at a couple examples of that later on in the lecture. OK. So let's do a quick recap of the things we've talked about so far. And so what we saw just now was an example of functions in JavaScript, where a function can be defined just by the word "function" followed by the name of the function that we want to define followed by, optionally, some number of arguments that that function is taking. And then enclosed in curly braces, we have all of the code that we want to run when that function is executed. So in this case, we want to run an alert that says "Hello World," or just "Hello," or something else. And in particular, we were calling these functions when particular events happened. So we saw that before, this hello function only happened when we clicked on a button, for example. When the onclick event was triggered, that resulted in the hello function being called. But there are other events as well. And so here are some other common events that you might see. This is not a comprehensive list, but some common events that may come up and that may be useful if you want particular blocks of JavaScript code to only run under certain circumstances or under certain conditions. So the onclick event was the one we just saw that happens if there's a button, for example, and someone clicks on that button. onmouseover is good if you want something to happen if someone hovers over a part of the window as opposed to having to actually click on it. So onmouseover works well for that. There are also keyboard events related to not what's being done with the mouse or with the cursor, but what's being done with the keyboard itself. onkeydown is an event that's triggered when someone presses down on the key. And when they release that key, that triggers the onkeyup event. onload is one that happens when something is finished loading, like when the entire window is finished loading with all of its images, and CSS resources, and everything else that's included in the window of the page. And onblur is also a common one that used when an object loses focus. So for example, an input field. If you're in the input field, and it's highlighted in blue, as you might commonly see, and then you click out of it, and it loses focus, you can use events like onblur in order to handle situations like that. And so by running different functions in response to different events, the result is that we can begin to build much more dynamic user interfaces, where it's not just that the server responds to the client, and the client sees a web page, and they can just view the contents of that web page, but they can actually interact with the web page. So they can click on buttons that trigger actions to happen without needing to request additional information from the server, but just because JavaScript code is going to be running inside of the user's own web browser. And so these events can ultimately help in order to make some of that possible. So now what we'll take a look at is how we might begin to use some of the information that we are able to look at inside of the DOM, inside of the Document Object Model, the contents of the web page, in order to write JavaScript that is able to access and manipulate the DOM-- in other words, using JavaScript code that actually manipulates the contents of the web page. So far we've just seen JavaScript used to display an alert, for example, but it actually is far more powerful than that. And so what I'm going to introduce is the idea of querying for something in the documents, searching for something inside of the document of the web page in order to make something happen. So let's take a look now at query.html. And so inside of the body of this web page, right now it just, again, has a heading that says "Welcome!" and a button that says Click Here, where, when we click on that button, it's going to trigger the hello function. But what's actually happening inside of the hello function? Let's take a look at it. So inside of these script tags, inside of the JavaScript contents of the web page, we've defined a function called hello, same as before. And that hello function is triggered whenever this button down here is clicked on. So when someone clicks the Click Here button, it's going to run the hello function. Now, instead of just alerting something inside of this function, let's see what's happening here. Document is just a variable in JavaScript that refers to the web document, the web page that we're currently displaying. And querySelector is a special function that will allow us to search through the contents of the web page for a particular CSS selector. So if you recall from way back when we were talking about CSS in the first and second weeks of the course, we had different ways of using CSS selectors in order to style particular elements of the text. You recall that we could say li, for instance, followed by some CSS code to style all of the list elements. Or we could use the pound sign in front of the name of an ID in order to style only that particular ID. Or the dot sign followed by the name of a class to style all of the different things that belong to that class. We can use that same syntax and the same sophistication that we could use in CSS selectors inside of this querySelector function, which will extract from the website one particular HTML element. So in this case, I'm querying for an H1 element. And if we were to search through this web page just using our own eyes, we would find that the H1 element is down here. And then we're accessing the .InnerHTML property of this H1 element. Any ideas what the inner HTML property of the H1 element could refer to in this case? So the H1 tag-- it's a good guess. So this is, in fact, the element. But the inner HTML would refer more specifically to-- yeah? AUDIENCE: [INAUDIBLE] SPEAKER 1: Precisely. The content in between the opening and closing tags of H1. So if I querySelect for the H1, that will select this H1 element. And the inner HTML of that H1 element is the HTML content that's contained within those tags. So in this case, it's just the word "welcome." And so now if I instead set that inner HTML to "goodbye," the result is that I'm able to use this JavaScript code to actually edit the contents of the DOM, edit the contents of the web page in order to change what's contained inside of the body of the page. Yeah, question? AUDIENCE: [INAUDIBLE] SPEAKER 1: Good question. So can you make a button called Multiple Functions? Certainly inside of these quotation marks here, we could add more sophisticated JavaScript that potentially did call multiple functions. But ultimately, this is going to start getting messy if we have a lot of different functions contained inside of this onclick attribute. We'll see very shortly how we can begin to factor some of this out of the actual HTML contents in order to use just plain JavaScript inside of these script tags that allow us to do much of the same thing. But yes, you can. Yeah? AUDIENCE: Will it change all the H1s if there were multiple H1s in the document? SPEAKER 1: Great question. What would happen if there were multiple H1 tags is the question? Would it change all of them? The answer is no. What querySelector will do is it will look through the web page for something, but it will only select the first thing that it finds. So if there were multiple H1 tags, it would only select upon that first one. We'll look at least one example later where we want to select for multiple things using querySelector. And we'll see how we can do that as well. But just this querySelector function will only select one thing that matches what we're searching for. So let's see this page in action. So this is query.html. So if I now open query.html, what I see is the word "Welcome!" in my big heading and this button that says Click Here. And recall, when I click the Click Here button, that will trigger the calling of the hello function, which, ironically enough in this case, changes the contents of H1 to say "goodbye" instead of "welcome." And if I refresh the page, now it goes back to "Welcome!" because I reloaded the entire page again. But clicking the button again takes me back to saying "goodbye" instead of "welcome." And so I've been able to manipulate the contents of the web page using JavaScript without needing to contact another server. I didn't load another web page that said goodbye. This is the same web page. I've just used JavaScript in order to modify the contents of what was actually on that page. Questions about anything so far? Yeah. AUDIENCE: [INAUDIBLE] SPEAKER 1: Is what case-sensitive? AUDIENCE: Attribute [INAUDIBLE]. SPEAKER 1: The property, I believe, is case-sensitive, yes. AUDIENCE: So something like a getID-- so it went [INAUDIBLE]. SPEAKER 1: Good question. So the question is about a different function called getElement by ID. And that is, I believe, case-sensitive. And the way getElementById works, which you won't actually see today, is it's very similar to querySelector except it will only select something by its particular ID name. And just to give you a brief overview of the simple things that you can do with querySelector, what we saw just now was using document.querySelector to select a tag, like an H1 tag in this instance. We could also have used querySelector to select for a particular ID just by using the pound sign in front of it. This is the equivalent of what getElementById would do or, alternatively, by a particular class just by using the dot in front of it. And this might be syntax you remember from way back when we were talking about CSS. And if you recall, we can also use the more sophisticated CSS selectors. Remember we talked about selectors that would allow us to access just the children of a particular type of element or looking at only input fields that were of a certain type. We can do all the same things using querySelector in order to extract from the HTML page just the element that we care about modifying in this case. So let's start to take all of these features and put them together into an application that does something a little more than just replace the contents of a heading, for instance. And let's take a look at counter0.html. And so counter0.html, I'll show you what it's ultimately going to do, and then we'll look at the code that makes this happen. Right now the button that says Click Here. And my heading, instead of being some text, is just the number 0. And you'll notice that when I click on Click Here, the 0 changes to 1. If I click again, it changes to 2. And then the more I click, the number will just keep counting higher and higher and higher, incrementing by one every time. So what is the code that I need in order to make something like this happen? Well, let's take a look at counter0.html. So first, let's look at the body of this code. I have an H1 and I've given it an ID. And I've called the ID counter. This is just so that later on I can access this particular heading by referencing it by its ID. Its ID is counter, and this gives me an easy way to get at this heading. And by default, it's just going to say 0 to begin with. And this Click Here button is the same as the buttons we've seen before. It's a Click Here button, where, when we click on it, we'll call the count function. What's now happening inside of the script? Well, inside of the script, the first thing we've done is define a variable. Just like variables exist in Python that allow us to store values and manipulate values, we can likewise have variables existing in JavaScript as well. And the syntax here for that is let counter equal 0. We've defined a variable called counter, and its initial value is going to be 0. And so that variable now exists inside of our page. And now underneath it, we've defined a function called count. And what the count function does is it will increment the counter. Counter++ is just another way of saying, counter equals counter plus one. It sets counter to be a value one larger than it. And then after we've incremented counter, we're doing document.querySelector #counter in order to extract the item that has ID with name counter. And then taking that HTML element, which is the heading down below, and setting its inner HTML to be whatever the value of this counter variable currently is. And so the result of that is that if counter begins at 0, then when I click the button for the first time and the count function gets called, counter on line 9 here is incremented to be 2 or 1 instead of 0. And then we select that heading and update the inner HTML of it and update the contents of that heading to be the new number. So questions about that code and how we were able to make that work? All right. So now we'll take a look at some other features that we can begin to use. We'll take a look at counter1.html. And in particular here, we'll start to look at conditions that we can add to code. So just like Python has loops, and conditions, and all of these other programming constructs that let us do interesting things with our code, we can do the same thing in JavaScript. Although the syntax is a little bit different, the ideas, fundamentally, are all the same. And so here we have, inside of our body, a heading that's called counter that starts off at zero, and a button where, when we click on it, it updates the count. And inside of these script tags here, we are going to define some JavaScript that's very similar to the code we've been using before. let counter equal 0 is the definition of our variable counter, which starts off at zero. And inside of this count function, after we increment the counter, after we update the inner HTML of our counter heading to be whatever the current value of the count is, we have this condition, which is that if counter % 10 equals equals equals 0, which you should read as, if counter mod 10, where mod is the operator where you take the remainder of one thing divided by the other-- in other words, if you take one number and divide it by 10, whatever the remainder is, that will be what counter mod 10 is equal to. And the triple equal sign is JavaScript's way of comparing things for exact equality. In other words, they have to be identical to each other in order for this to hold true. So if counter mod 10 is equal to 0, then we alert and say the counter is at-- and here, this is an interesting feature of the more recent versions of JavaScript, including ES6, where this is known as a template literal. You think of them like formatted strings in Python, where I want to alert something, but I don't just want to alert some string that is always going to stay the same. I want to dynamically generate that string with some contents of variables that exist inside of my JavaScript code. And so to do something like this, the way you would do that is instead of using quotes, either single or double quotes as you normally would for strings, we're using that back tick symbol, which, on US keyboards, is right above the Tab key. And we say in this alert, the counter is at-- and then to plug in a variable, the way we do this in JavaScript is to use the dollar sign and then, inside of curly braces, the name of the variable that we want to plug in. And so here, we're saying, counter is at-- and this code here is saying, take the variable counter and just plug it in to this part of the template string. So it's the back ticks around the string, and then the dollar sign, and the curly braces that allow me to format the string and treat it like a template that I'm able to plug in certain variable values into it. So what do we think the result of running this web page is going to be? How is the behavior going to be different than the example we saw just a moment ago? In particular, what will this if condition inside of the count function do? Yeah? AUDIENCE: [INAUDIBLE] SPEAKER 1: Great. Every 10 times we click the button, it should pop up with an alert, because every 10 times we click it, when we get to counter is 10, then 10 mod 10, 10 divided by 10, leaves a remainder of 0. And so 0 will be equal to 0, and then we'll get the alert. But in other cases, we won't. So if we now open up counter1.html, we can count just as we did before. But it's only when we are at 9. And when we click again, then we get the alert saying that the counter is a 10. And if we were to continue counting, when we get to 20, it would give me another alert, 30, so on and so forth. And so this allows us to have a little more control. Just like we were able to have if conditions inside of Python, we do the same thing in JavaScript. And like the distinction between functions in Python and JavaScript, the way that we denote the contents of an if condition in JavaScript is to enclose it inside of curly braces. Strictly speaking, this is only necessary for if conditions that run onto multiple lines. If the condition were just a single line, as it is now, the curly braces aren't, strictly speaking, necessary. But oftentimes, they're good just as a visual cue so that anyone looking at the code can see what is contained inside of the if condition and what is not. Questions about any of that so far? OK, great. Now let's take a look at counter2.html. And so in this case, what we've done is if we look down at the body before we look at the actual contents of the JavaScript, we'll notice that one thing is different here. We have H1 id is counter is 0, and then a button that says Click Here. What is different between this and all of the other buttons that we've seen so far? Great, the onclick property is no longer present. So I have this button that says Click Here, but I don't have anything that is saying, when this button is clicked, here's what you should do. Or at least it doesn't appear to be that way. What we'll soon see is an attempt at trying to take all this JavaScript logic and JavaScript code, and factor it out of the HTML. So I don't need to have JavaScript code inside the body of the HTML contents in order to tell the button what to do. But instead, I can put it all inside of these script tags. And so this looks, in between the script tags here, a little more complicated, but let's take it one step at a time and see if we can understand what's happening here. So up on line 6, we have document.addEventListener. So we haven't used addEventListener before, but we have talked about the idea of events, that when something is clicked on, that's an event; when you mouse over something, that's an event. It turns out that the document, the web page, has an event that almost all modern web browsers support called DOMContentLoaded. And that event is the event that's triggered when the DOM, the Document Object Model, that structure of all of the HTML tags inside of our page, is done being loaded by the web browser. And so when that is done being loaded, when we've loaded the web browser, now we can start to do some interesting work. And so what we've done is we've called this addEventListener function, which really takes two arguments. It takes, as its first argument, the name of the event that we want to listen for-- in this case, the DOMContentLoaded event. But the second event is actually a function. And so JavaScript allows us to do what are called higher order functions, where we can treat functions themselves as values. And if we want to take a function and pass it into an argument to another function, the same way we would pass an integer into a function or a string into a function, for example, JavaScript allows us to do that. Python allows us to do it too, and it's a feature of many modern programming languages nowadays. But we can take this whole function that starts with function and is enclosed inside of these curly braces, and pass that whole function in as the second argument to this addEventListener function that we're calling here. And this parenthetical at the end is closing the argument list to addEventListener. And so what does this all mean? It means that we're telling the document that when the content of the DOM is loaded, this is the function that should run. It's not going to run right away. It's what we might call a callback function. When the content of the DOM is loaded, then JavaScript is going to call this function and it's going to run the contents of that function only when that event listener is done running. So what are we saying here? Inside, when the DOM is done running, we're going to document .querySelector button-- in other words, extract the button from the page. There's only one in this case. But as was mentioned before, if there had been multiple buttons, querySelector would just select the first one. And then we're setting the onclick attribute of the button. This is effectively the same thing as what we were doing before, where we actually had the button tag and we said, onclick equals-- here's what to do. And we're setting onclick equal to count, where count is also itself a function that's defined down here. And this is the same function that we've been looking at before that just increments the counter, updates the HTML of the heading, and then has this if condition that alerts or doesn't alert. But we're taking that function and treating it like a value, which JavaScript allows us to do. And we're saying, when the button is clicked on, what should you do? Run the count function. Again, that count function won't run right away. It will only run when that button is clicked on. So questions about these three lines of code in particular that are sort of strange to wrap your mind around at first-- treating functions the same way you would treat any other values, like numbers or strings. But ultimately, this is one of the most powerful features of JavaScript, which is the ability to take functions and pass them as arguments into other functions, and to set them as callback functions that only run when certain things happen. Yes? AUDIENCE: Does that mean we can't create a variable called count in the function [INAUDIBLE],, if we just try to create a variable without [INAUDIBLE]?? SPEAKER 1: If you tried to create a variable called count, you would likely get namespace collision from that case, in which case you would try to avoid that. Yeah. AUDIENCE: Why is this better than just explicitly putting the count function as the onclick attribute when you create the button [INAUDIBLE]? SPEAKER 1: Great question. Why is this any better than just putting the onclick inside of the button inside of the HTML, which seemed a whole lot simpler as opposed to this complexity of DOMContentLoaded and such. As sites start to get more and more complex, you'll see added value that we can get out of this. For example, if we had 100 buttons and we wanted all 100 buttons to do something in particular when they're clicked on, we could go through all 100 buttons in our HTML and add onclick attributes to all of them. Or we could, in JavaScript, do things a little more programmatically, and try and select all of the buttons, and give them all an onclick attribute in some loop, for example, which would be slightly cleaner in terms of using programming structures like loops and conditions in order to modify the attributes of the events. And in other cases, you might want a little more control over what happens when you click on a button. You might want a button to do one thing in certain situations and another thing in other situations. And being able to programmatically say "if something is true, then set the onclick attribute to count; and if it's not true, then something else" gives us a little more flexibility there. And finally, it's just a little bit cleaner. That inside of the body of the HTML now, we no longer have any JavaScript code. So if I need to change anything in terms of just the JavaScript, I only need to change what's inside the contents of the script tags. And we'll see another example of factoring this out even more in just a moment. But good question. Was there another question someone had? All right. So this was just allowing us to add an event listener for when the DOM is done loading. And we'll see this syntax quite a lot in the examples today, where when the DOM is finished loading, then we want a particular code to run. So this is an example of us trying to factor out some of the JavaScript code from the HTML that's down below into this script tag. But what we might like to do is factor this out even more and put the JavaScript code not just at the top of the HTML file, but in a second file altogether. Now, aside from just cleanliness and moving things out into separate places, what might be a reason why we might want JavaScript code factored out into an external file instead of inside of the same file as everything else? Yeah? AUDIENCE: You can reuse it. SPEAKER 1: It's reusable. Great. If I had multiple HTML files that wanted to use the same JavaScript, I could just reference them all to the same JavaScript file in much the same way that, when we were designing style sheets in CSS, we could factor them out into a separate CSS file such that multiple different pages could use the same CSS style sheet. And so what would this look like to try and factor out our JavaScript into a separate file? Let's take a look now at counter3.html. And this is the same thing, except instead of something inside of the script tags, I've just said, script src equals counter3.js. counter3.js is the JavaScript file that contains all the JavaScript code that I care about. And in the body, I just have a heading and a button. But inside of counter3.js, this is all the same JavaScript as before. Add the addEventListener for when the DOM content loads, which adds count to be what happens when the button is clicked on. And then I have the count function here, which actually does the incrementing, and the query selecting, and the alerting. And so this allows us to factor that JavaScript out even more, helps to clean up the contents of the HTML page. It also makes it reusable, as was just mentioned. And so these are more examples of how we can begin to clean up the code that we've been writing. Questions about anything so far? OK. I'll talk briefly about variables just for a moment. The latest versions of JavaScript have a bunch of different ways to define variables. And we've seen the example of let counter equal 0 to be one example of how variables might be defined in JavaScript. But there are actually multiple ways in which we can use variables. And there are three that are the most common-- const, and let, and var. And so we've seen let in the example that we just used. But I'll talk about the distinction between these three. const is the variable type that means a constant value, as you might guess from the name. And so if I define a variable as a const variable, then I can't reassign it later. If I try to reassign it to some other thing later on in the JavaScript page, it's going to give me some kind of error. And so it's useful if I want to define a variable that I know is not going to change. And it can help to avoid potential bugs later on down the line where I might try to change it even though it shouldn't be changed. And so this just helps to enforce that that variable's value will not change. let is the example of the variable that we've been using so far, where let will exist inside of the scope of the innermost curly braces surrounding it. And you'll see an example of that in a moment. But in particular, if you define a variable with let inside of a block of curly braces, then outside of that block of curly braces, that variable will no longer exist. As opposed to var, which operates similarly to let but slightly differently. If you define a variable as var, then it will exist all the way inside of whatever function it was originally defined in if it was defined inside of a function even if it was included in an enclosing set of curly braces. And so that was sort of a lot of complexities and nuances between the three. We'll take a look at some examples of those variables actually in action now, so that you can get a sense for when you might use one of these variable types over another and how their behavior differs a little bit. So let's take a look at variable0.html. And so all variable0.html does is if true-- so if true is true, which is always true, so this condition will always run-- we set var message equal to Hello! And then we alert with that particular message. And because it's defined as a var, then it's going to exist even outside of just the contents of that if condition. And so if I now open up variable0.html, I get an alert and this page says hello. So it behaves as we might want the page to behave, because I define it as a var and even though it's inside this span of curly braces, when I alert, it alerts with the correct value of message. variable1.html instead is going to use let instead of var. So the only change here is that instead of var message equals Hello!, I've said, let message equal Hello! And then down below, I get an alert that says alert message. Any guesses as to what might happen now if I try to open variables1.html? A blank alert. That's a good guess. Other thoughts? An error. All right, let's try it out. Let's see what happens. Let's open up variables1.html. And it just says "Welcome!" and I don't see anything so far. And I also don't see an error message just yet. And so one thing to look for if the page doesn't seem to be doing what you might initially think it might be doing is to actually look at the JavaScript console, which is built into most modern web browsers, and just take a look and see if there actually were any errors. And so an easy way to get to that, in Google Chrome at least, is to Ctrl-click on the page and go to Inspect, which opens up the Inspector. And if I click over here now to the console, what I get is the actual JavaScript error. And so this is where JavaScript errors are going to appear if I'm running them in the web browser, because all of the JavaScript code is running inside the web browser, inside of Google Chrome. And so any errors that pop up are going to be part of-- they're going to show up inside of Google Chrome. And so this says, "uncaught reference error, message is not defined at variables1.html:11," meaning line 11. And so if I go back to variables1.html, line 11, this is that line. And the reason why message is no longer defined is because let only defines the variable in the scope of the outermost set of curly braces. So this is very similar to how programming languages like C treat their variables, where the variables are only existing inside of the scope in which they're defined based on those curly braces. And finally, we'll take a look at one other example. We'll look at variables2.html, where, in this case, we have const message equals Hello! And now I'm trying to reset the value of message. Message equals Goodbye! And then I'm going to alert that message. Guesses as to what might happen? Plenty of reasonable guesses here, but let's-- what do we think? AUDIENCE: Another error. SPEAKER 1: You could get another error. And in fact, that's exactly what's going to happen. We see "Welcome!" We don't see any error message. But if I go ahead and inspect this and go to the console again, we see "uncaught type error, assignment to constant variable at variables2.html, line 8." And so we're not allowed to take a const variable and reassign it to something else. And so here on line 8, trying to set message to be "Goodbye!" before we alert it is not going to be something that JavaScript allows us to do, whereas if we had defined a variable with let or var, then we could have. So three slightly different ways of defining variables that result in slightly different behavior. It's good just to understand all three and to know how they behave in different circumstances. And those are just different ways of how we might go about using variables in our code. Yeah? AUDIENCE: Is there a default if you don't say what it is? SPEAKER 1: If you don't specify what it is, I believe it will default to binding as if it were a var, but I'm not 100% sure about that. I'll have to check on that. Good question. Other things? OK. One other interesting thing to note about this JavaScript console that we're looking at here inside the web browser is that it actually allows us to execute JavaScript code in much the same way as the Python interpreter allows us to execute code here as well. So for example, if I wanted to define another variable, like let x equal 28, I can just type JavaScript code into the console here. And if I type "x" now, for instance, that's going to be equal to 28. And that's something that you can do inside of this JavaScript console. So if you're ever confused as to what exactly is going on here, oftentimes it can be a good idea to use the JavaScript console, run some JavaScript code in order to get a sense for what's really happening. For example, if I were to run document.querySelector, h1, then what I get back is it'll actually show me what happens when I run document.querySelector h1. Well, it gets me that h1, "Welcome," exclamation point, end the h1 tag. And so you can see what the actual result of running some of this JavaScript code would be. And likewise, if I tried to run document.querySelector, h1, .innerHTML to see what's the inner HTML contents of it, then I get just that string, "Welcome!" as the result of that. And so this can often be a helpful debugging tool if you're trying to understand what's going on inside of your JavaScript code, where you can actually run JavaScript inside of the console in order to manipulate things and change things. And one nice example of that, actually, is if I go back to our counter one example, this example where I could click here and just increment the counter again and again and again, if I wanted to, I could go here and say, what is the value of this variable counter? It's currently 7. If I set counter equal to 27 instead, what's going to happen when I click here? 28. Exactly. Because I've reset the value of counter, you can actually manipulate the values of variables inside of the JavaScript console and make manipulations however you like them. And you can see the results actually appear on the web page. I can do document.querySelector, h1 to get at that counter. And if I set the innerHTML to be "Hello," well, now I've just changed the contents of the web page to be, instead of 28, now it says "Hello!" But as soon as I click here again, it increments the counter and resets the contents. So this allows you to manipulate web pages using JavaScript, using the console in that way as well. Questions about anything we've gone over so far? OK. Let's take a look at a couple other more common use cases that we might find with regards to JavaScript. Let's take a look now at hello1.html. So we saw an example of an alert that just said "Hello!" Let's take that to another level now. Inside the body of our web page in hello1.html, we have a form whose ID is form just to make it easy to reference later. And I have an input field. This ID is name-- again, just to make it easy to reference later. And the placeholder that we're going to fill into the input field is just going to be the word name. And it's going to be an input field where I can type text. And underneath that, I'm going to have an input whose type is submit. That's just going to be a button that allows me to submit the form. So now what is going on inside of my JavaScript? Well, when the DOM content is loaded, I'm going to run this function. And what am I doing here? I'm running document.querySelector #form .onsubmit. Onsubmit is yet another event that we've been looking at. We thought when something is clicked on, that's an event. When something's moused over, that's an event. When the DOM content is loaded, that's an event. When a form is submitted, that's also an event. And so what's going to happen when this form is submitted? We're going to run this function, again, passing this function in to be the value of this onsubmit attribute of my form. And I'm defining name as a const, because it's not going to change, equal to document.querySelector #name .value. Any guesses as to what that's going to extract? What is querySelector #name .value? Yeah? Great. It's going to be whatever the user typed into that text box, because that text box had an ID of name. And so if I querySelect for #name, that's going to get me just that HTML input field. And if I get the value of an input field, the value of the input field is whatever it is the user was typing in to that input field. And then I'm going to alert. This is, again, one of those template literals, those formatted strings, where I'm saying "hello" and then plugging in the value of that name variable there. And so I'm going to say hello to whoever typed in their name. So if I go back to the actual page and open up hello1.html, if I type in "Brian" and press Submit, it says "Hello, Brian." If I instead type "Meredith," for example, and press Submit, then it says, "Hello, Meredith." And so I'm able to use the contents of the value of the input field to dynamically create whatever alerts that I wanted to create, in this case. But I could have done anything with this name variable. I'm just using JavaScript now to extract information out of the form. Questions about that so far? Yeah. AUDIENCE: So you call it a constant? But then you're able to do it twice. Isn't that changing your constant? SPEAKER 1: Great question. So it was a const variable, but I was able to use it twice, right? I typed in my name and it said "hello, Brian," and then I typed in Meredith's name and then it said "hello, Meredith." What's going on there? Why did it let me do that? Any guesses? Well, one is that the page reload. Yes. Certainly. Because when the form was submitted, it ended up going to the page again. But another thing to bear in mind is that const here is located inside of the scope of the function, which becomes relevant as well. All right. Let's take a look at-- so we saw now that we can use JavaScript to be able to access the HTML contents of the page. Now let's take a look at using JavaScript to modify the styling of the page as well. So let's take a look at colors0.html. I'll show you first what color0.html is going to do. This web page says "Hello!" And it's got two buttons at the bottom-- Red, Blue, and Green. And when I click on those buttons, Red changes "Hello!" to red, Blue changes "Hello!" to be in blue, Green changes it to be in green. And so how is that working in terms of the code? Well, here in the body of the page, I have a heading that says "Hello," then a button whose ID is red, which just says Red; a button whose ID is blue, and that button's labeled Blue; and a button whose ID is green, and that button is just labeled Green. And now what's here inside of the script tag? Well, I have document.addEventListener DOMContentLoaded. So here is the code that is going to run when the DOM is done loading when we're ready to actually do interesting things with the content of the site. I say, document.querySelector #red onclick, meaning when the Red button is clicked, this is the code that should run, this following function. And so inside of this function, we have document.querySelector #hello getting that thing with ID hello, which was that heading that says hello. .style gets at its style attribute. And then I can modify any of the CSS properties that I had. Remember that we had CSS properties for the color of something, or the font size of something, or the background for something. And any of those CSS properties I can now modify by accessing this .style attribute of the HTML element. So I'm saying .style .color. That's going to be equal to red. And likewise, I'm doing the same thing for when I click on Blue. Then I change the color of the "Hello!" element to be blue. And likewise, when I click on Green, I change the color of that to be green. Questions about how that was able to work? Anyone see areas for improvement in this code? Something that might look suboptimal, at least at first glance? Yeah. AUDIENCE: [INAUDIBLE] SPEAKER 1: Yeah, I have three functions that are all really doing the same thing. I have a Red button that changes the "Hello!" to be red instead of black or whatever it was originally; a Blue button that does the same thing; Green that does the same thing. And this is happening because querySelector, as we've seen it so far, really only allows us to extract the first element that it finds. So I'm extracting the Red button and then doing something with, extracting the Blue button and doing something with that. And these functions are slightly different. And so what I'd like is for some way to generalize this, to be able to only need to write this code once, and then have it apply to all of these different buttons. And so there are a number of different ways to do that, but we'll take a look at one way right now. And so here what we have inside of the DOM Content Loaded section is, instead of document.querySelector, I have document.querySelectorAll. And what querySelectorAll is going to do is instead of just selecting the first thing that matched, as querySelector did, querySelectorAll is going to return to me an array of all of the things that matched the query that I was trying to perform. And so here, I'm querying for anything that has the class Color-Change. In particular, as we'll see down below in the HTML contents of the page in just a moment, I've given all of these buttons the class Color-Change. And as a result, when I querySelectorAll for anything with the class Color-Change, the result is that I'm going to get back an array of all of those different buttons. Then after that, I have this .ForEach. And so ForEach is a built-in function that we can use on JavaScript arrays that allows me to run a function on each element inside of that array. And so ForEach is another example of a higher order function. ForEach is a function that is taking, as input, yet another function that I want to do something interesting with. And it's a function that is going to take, as input, one particular element of that array. And so before we go on to seeing what that function actually does, let me show you the HTML content of this page. So inside of my body, I have this heading that says "Hello!" I have three buttons. All of them have this class, Color-Change, that is going to be the class that allows me to select all of them at once. By selecting everything that has the class Color-Change, I can select all three of those different buttons. And then what you'll find is I've added this data-color attribute to all of my buttons. Now, data-color is not just some attribute that is built into all buttons, but rather it's an example of a data attribute where, in HTML oftentimes, if I want to associate additional data with an HTML element that's not displayed on the page, I can put it inside of a data attribute with the name of my own choosing so long as it begins with data, hyphen, something in order to give that HTML element a little more information about itself or information that it would need to know for purposes of being used later, oftentimes in JavaScript. And so what I've done here is I've defined these buttons that all have class Color-Change, but they all have this color data attribute, data-color, which is equal to the color that they should try to turn the text into. So this one has data-color red, the Blue button has data-color blue, the Green button has data-color green. And how do I actually use these data attributes? Well, if we look back up here at the JavaScript code, when I do this querySelectorAll selecting for all of the buttons, or all of the HTML elements that have the class Color-Change, I'm saying, ForEach-- in other words, run this function on each one of these individual buttons-- here is that function. That function takes, as input, one of those buttons. It's going to first operate on the first button, then the second button, and then the third button. And we're setting the button.onclick property of each to be this new function. So this is the function that should run when we click on that button. document.querySelector #hello .style .color is the same thing we've seen before. We're going to take that heading, that "Hello!" heading, get at its style attributes, and change the color of its styling. And in particular, what color do we want to change its styling to? Well, we want to change it to whatever that data-color attribute of the button itself was. And so we have access to this variable button, because the ForEach function will loop over each element in the array and let us run a function, passing in just an individual element as input. And we called that button. And in JavaScript, to access any of the data attributes, we use the .dataset property. And so by going to button.dataset.color, what that's going to do is it's going to take that button, extract its data attributes-- in this case, data-color-- and get at one particular attribute. In this case, we want the color attribute. And so the long story short of what all of this is doing is we're selecting for all of the different elements that have the Color-Change cloths, which is all the buttons. And for each one of those, we're going to run this function that sets the onclick property of that button to be a function that takes the "Hello!" heading and changes its color to be whatever the data-color attribute of that button originally was. And the result of this is that colors1 behaves exactly the same way as color0. They have these Red, Blue, and Green buttons. And when I click on individual ones of them, it causes the color of that "Hello!" heading to change all based on this dataset property. And we were able to do that now using just a single function that changes the color as opposed to color0, where we needed three different functions, one for each of those individual colors. Questions about any of the stuff that was happening here? So this is a lot of new syntax. Yeah? AUDIENCE: [INAUDIBLE] SPEAKER 1: Good question. So what happens if we try to inspect one of these buttons inside of the Chrome Inspector? So I can do document.querySelector. And I'm just going to select for just an individual button for now. And remember, the querySelector only returns one thing. So even though there are three buttons here inside of the HTML document, running querySelector on button is just going to return to me the first button, the Red button. And if I do onclick, what I get back is that function. This document.querySelector #hello is equal to whatever the button's data set color is, because I've updated the onclick attribute of that button to be that new function. Great question. Other things? All right. So inside of colors1.html, what you've likely noticed now is that we have a lot of these different functions. Here's a function that doesn't take any parameters. Here's another one that doesn't take any parameters. Here's one that takes button as a parameter. Functions are incredibly common in JavaScript, as we've seen already, because we have these callback functions that are called whenever events are fired. And in the latest versions of JavaScript, ES6 in particular, they've introduced a new syntax for functions that makes things just a little bit simpler to deal with. And so I'll introduce that syntax now, and we'll use it for the remainder of the lecture today just to give you a taste for it. So inside of colors2.html, which is going to do exactly the same thing, we're going to introduce this arrow notation syntax. And let me briefly talk about what that arrow notation syntax looks like to define what are called arrow functions. And then we'll take a closer look at them, actually, in practice. And so this is an example of an arrow function that takes no arguments. And so in particular, an arrow function is defined without the use of the word "function." And instead, it just has any arguments the function takes, with the just empty parentheses meaning no arguments, followed by equal sign, arrow just to be an arrow, meaning, take this as input and then run this code. And so this is just ES6's way of defining functions. You can use functions the old way just as well. And these functions behave very slightly differently, as we'll see later on today, but are, in fact, just a more succinct, more compact way of writing functions in ES6. And so this is a function that takes no arguments and just alerts "Hello, world!" in much the same way as that hello function that we saw earlier this evening did. And this, for example, is a function that takes, as input, a variable x as its input and then, in the body of the function, alerts whatever the contents of x was, for example. And you can see these functions represented even more succinctly. If there's a function that's just taking input and returning a value almost right away, you can, in fact, represent a function as simply as this, where you have an x, arrow, x times 2. This is a function defined in ES6 that takes, as input, a number x and returns whatever x times 2 is. And no curly braces required in that case either. So these are just more succinct ways of representing functions. If you take a look at modern JavaScript code, you'll see syntax like this a lot. So I just wanted to introduce it to you to give you a feel for what it is and how it works. And so if we were to take that color example and rewrite it using arrow functions, it would just look something like this. Instead of after DOMContentLoaded function and then the curly braces, we would just say, parentheses, meaning this takes no arguments; followed by equal sign, arrow; and then the contents of what should happen when the DOM contents is loaded. In the example in the old example, when we were running that ForEach function and we had a function that took, as input, the button, and then ran all of this code in here, in the new example with arrow functions, we would write that as button-- that's the input-- then arrow. So button is the input. And then this is what should happen in the body of that function. When the button is clicked, then run a new function that takes no arguments. And then runs this code as a result. So colors1 and colors2 are effectively doing the same thing here. We're just using the new ES6 arrow function notation to achieve the same thing in just a slightly more concise way. And it's just good to see examples of both, so that you know that both are perfectly reasonable ways of writing these functions. Questions about anything so far? OK. We'll take a look at one last example before we take a short break. We're going to take a look at colors3. And so in colors3, what you'll notice is-- I'll show you how it works first. It says "Hello!" And instead of three buttons, we have a dropdown box. It starts off as black. We also have red, blue, and green. And what this dropdown box will do is whenever I select a new color-- I select red, for instance-- then it changes the contents to red. Blue changes it to blue. Green changes it to green. So slightly different. But we'll see how that's implemented as well just to give you another example. So in colors3.html, I have a heading. It just says "Hello!" Same as before. Instead of buttons, I have a select dropdown. Select id is color-change. And I have all these individual options. Each option is an option in that dropdown list. What's enclosed in between the option tags is the actual text of the option, which would show up to the user. Each one also has a value. And that value I'm going to use JavaScript in order to extract. So the value of each is just whatever the actual string of the color that I want to change "Hello!" to be in is going to be. And now inside of the script contents of the page, when the page is done loading, here's what should run. Document.querySelector color-change. So color-change is that select dropdown. And onchange, as you might guess, is yet another event. So onchange is the event that gets fired when I change my selection in the dropdown box of the Select menu. And when that happens, I'm going to run this function, which gets at "Hello!" and change style.color to be this .value. And so the only really new thing here, aside from the onchange event, which should hopefully be pretty straightforward if you've seen examples of other events already, is this keyword "this." And what does "this" refer to? Well, "this" will, generally speaking, refer to whatever value this function is being operated upon. And so in this case, "this" refers to document.querySelector color-change-- in other words, what I got when I extracted out that color-change ID, because I'm setting this function to be this onchange function, what happens when I change the color-change dropdown. And so this is whatever that select dropdown is. And so if I take that select dropdown and get at its value, that will be whatever the color is. And this is a little more sophisticated than you'll need to really worry about for purposes of just this class. But the way "this" knows what value it should be bound to, so to speak, what value "this" should take on is based on the function in which it is defined. And the long story short of it is that "this" will only be bound to the thing that you're calling the function on if you are using functions in the traditional functions without actually explicitly writing the word "function." If you use arrow functions, then "this" will instead be bound to whatever "this" was bound to in the code that was enclosing that arrow function. So long story short, doing "this," for instance, would not produce the same effects, because "this" would no longer be bound to the color-change dropdown. It's this keyword function and defining a function in the traditional way that allows "this" to be bound to the thing that I'm actually trying to modify. And so as you go about experimenting with functions and maybe writing some functions this way and some using arrow functions, you may run into being tripped up by when "this" takes on one value as opposed to another. A good way to begin to debug this, again, is just to use the debugger. And we'll see more examples of that later. But for now, we'll take a short break. And when we come back, we'll take a look at more examples of using JavaScript. And then we'll integrate JavaScript back in with Python to build dynamic web applications in Flask, but use both Python and JavaScript as well. But all that in a couple minutes. OK. Welcome back. So so far, we've been taking a look at JavaScript, looking at ways that we can use it in order to manipulate the DOM by editing elements that exist there already or by reading elements and values from dropdown boxes and input fields in order to do interesting and useful things. What we'll take a look at now is yet another example of how we can actually add things to the DOM, how we can add to the contents of the web page, adding elements that weren't there before in order to do interesting or useful things as well. And so I'll show you what we're going to try to build up towards, and then we'll look at the code that'll actually allow us to do that. So open up tasks0.html. And what tasks0.html is is it's a simple to-do list application, where I can keep track of different tasks that I need to perform. So here's a thing to do. And when I click Submit, it adds "thing to do" as one of my tasks. And I add "another thing," and I click Submit. There's another thing that I need to do. And it will just continue to maintain this ever-growing list of tasks that I need to complete based on what I type into the New Task input field and then clicking on the Submit button to add that to the list of tasks that I need to perform. And all of this is just happening using JavaScript. So let's take a look at the code that we would need in order to make that happen. Inside the body of the HTML so far, we have a heading that just says "Tasks" at the top, then a UL, or an unordered list, whose ID is task, just so we can reference it later. And to begin with, that unordered list is empty. It has no list items inside of it, which seems sort of strange, because in all of the unordered lists or ordered lists we've seen before, they've had within them li, list item elements, that define the contents of the actual list. But to begin with, we have no tasks to start out with, and so we need to start with an empty list and wait for things to be added before we can populate that unordered list. And then I have a form, whose ID is new-task. And inside that form, I have two parts to the form. One is just an input field. Its type is text, because I'm going to be typing in the task. Its placeholder is just New Task. And then I have this submit input field, which is just going to be that button. When I click on it, it will cause the task to be submitted. So what is the actual JavaScript code now that makes all of this happen? So when the DOM content is loaded, here is what I'm ultimately doing. Let's take a look at this code. So document.querySelector New-Task. New-Task is the ID of that form, the form that contains the input field and the button for submission. When I submit the form, here is the function that should run-- all of this code enclosed in curly braces. I'm creating a constant variable, a constant inside of this function, at least-- it's not going to change-- called li. And I'm setting that equal to document.createElement li. So I'm creating a new element, and the tag of that element is going to be an li tag, a list item tag. And then I'm setting li's inner HTML to be whatever the task's value is. Remember, the task here is the ID of that input field. And extracting its value will get at to mean all of the text that the user typed into that input field. And now, once I have this list item-- it's a new list item element and its inner HTML is whatever was inside that task-- I need to now actually take that new element and put it into the website somewhere, because I've created the element in the document, but I haven't yet told JavaScript where inside the DOM tree, where inside the page should this new list element go. And so what I'll do is document.querySelector Tasks, getting the thing with ID Tasks, which is that unordered list. And append to it. And these HTML elements have all sorts of properties that you can look up in terms of what they do. Append just happens to be one that adds a new thing to the end of it. And I can append to it li, which is this variable that I created here. And that's going to actually add the new item to the task list. And afterwards, we're going to do a couple other things. We're going to select that Task input field, set its value to the empty string. And so all that's going to do is it's going to take the input field that I started out with, and it's just going to clear it. So that I've already typed the task, the input field should clear now, because I've already submitted it. And then return false. So normally when you submit a form, the default behavior for submitting a form is that I'm submitting a form to some other website and it's going to try and load that new website. And if I don't specify, it's going to try and reload the same page again by trying to submit the form to it. return false stops the form from submitting to some other website, from trying to reload some new page, because I want to stay on the same page when I'm done submitting this form. And so we create the new element, we set its contents to be whatever the task is, add it to my list of tasks, clear the input field, and then stop the form, ultimately, from submitting. And that's what allows us to get this behavior, where we have a list of tasks and I can add more tasks to it. Now, there are certainly areas where I could improve upon this application. Right now if I just click Submit over and over, I can keep submitting blank elements again and again. So maybe I'd like to prevent that from happening. I'd like to make it so that I can't submit anything unless I've actually typed text into this New Task field. And so how might I go about doing that? Let's take a look now at tasks1.html, which is similar but we've added some additional JavaScript code. So up here, the first thing that I do is get the Submit button-- whose ID is Submit, I've given it the ID Submit-- and I'm setting one of its HTML properties. I can edit any of the HTML properties of an HTML element using JavaScript. And one property that's going to prove particularly useful here is the disabled property of a button that just determines whether or not that button is disabled or not, whether or not I can click on it. And so I'm setting the disabled property to true. And now I have document.querySelector Task-- again, that's the input field-- onkeyup. When I press a key, when I lift that key up, I've typed in text now, and so what should happen when I lift up that key? Well, now I've typed in text into the input field, and so the Submit field's disabled field can now be false. Because I don't want the Submit button to be disabled. And then onsubmit works effectively the same way. When I actually click the Submit button, I still want to add that new task to my list of tasks. But in particular, in addition to clearing the input field, I also want to disable the button again. So I querySelect for the button, which has ID submit. And I set its disabled property to be true instead of false. And so the result of that is that I have this list of tasks. I can start typing in one task here. And notice that the Submit button is disabled. I can't click the Submit button and submit an empty task. And it's not until I type in a second task that I can actually click on the Submit button and submit yet another task. So that allows me to manipulate the HTML attributes of the Submit button, setting its disabled property to true or false depending on what I want it to be. Anyone spot a potential bug with my implementation? An area where that might go wrong? Yeah? AUDIENCE: [INAUDIBLE] SPEAKER 1: Great question. If I-- or great answer. If I type something, some text, and then I erase it, and now I've gone back to the empty task field, now the Submit button is still active, and I can still submit a task. Why was I allowed to do that? Yeah, because I made a keystroke. And technically, hitting the Delete button is still a keystroke. And when I lift the Delete button, that's a keyup, as well as all the other characters that I was typing before it. So I'm going to need something a little more robust in order to allow myself to deal with this situation. And so we'll go ahead and fix this bug inside of tasks2.html. And so here, onkeyup. When I lift up the key, when I type in a new key into the input field, I went to check. Let me query for the task input field, get at its adds value, and I can use the .length property of a string in JavaScript that just gets me the length of how long a string is. And if the length of the string is greater than 0-- in other words, there are more than zero characters inside the input field-- then yeah, I don't want the button to be disabled. So disabled equals false. Otherwise, if there were zero characters inside the input field, then I want the disabled field to be true instead. And so the result of that is that the Submit button is disabled. I can add one task. It's disabled again. If I start typing in a second task but then delete, delete, delete, delete, once I empty out the whole thing, now the Submit button is disabled again. It's enabled here, and now it's disabled. And so this allows me to dynamically, using conditions and using event handlers, begin to make my user interface better and better by making it dynamic, making it responsive to what it is that the user is actually doing. Questions about anything so far? So a couple of people have asked about jQuery, which is a library you may be familiar with. We're not going to talk about it at all in today's lecture, but jQuery just happens to be a JavaScript library that is commonly used in order to do similar things, so the things we've been seeing so far in terms of selecting, and updating HTML elements, and updating, and modifying the DOM. Ultimately, jQuery's become slightly less popular in recent years as JavaScript itself has become more and more powerful without the need to use an external library like jQuery. Using things like querySelector and querySelectorAll, you can do much of the same stuff that jQuery was good with relative efficiency. And so jQuery, as a relatively large library that takes time in order to load and might slow things down a little bit, is becoming slightly less popular, although you will still see it in many instances. In fact, if you are using Bootstrap for any of your projects, for example, and are using any of Bootstrap's JavaScript features, Bootstrap is still using jQuery as a library in order to do most of its JavaScript work. And so you might stumble across jQuery-like syntax if you're looking at either Bootstrap's JavaScript or JavaScript on some other web pages or other libraries. And so just wanted to make you all aware of what jQuery is even though we're not going to look at it too much in today's lecture. We'll take a look, though, at a couple other features that are built into JavaScript itself. In particular, let's take a look at interval.html. And so interval.html, inside the body, just has a heading that says counter. There's no longer a button. But let's take a look at what's happening inside of the actual script contents. When the DOM content is loaded, I'm calling the setInterval function, a function built into JavaScript. And the setInterval function takes two arguments. The first is another function-- in this case, count, which is a function. And the second is the interval at which I should call it. And so setInterval count 1,000 is saying, call this count function every 1,000 milliseconds, every second. And the count function is the same as the count function we've seen before. It takes this counter value and it increments it every time. And so the result of this is that without needing to click on any buttons, if I open up interval.html, it'll start at zero and will count one, two, three, four, counting one number per second without my needing to click on any buttons. JavaScript is just running my count function one time every 1,000 milliseconds. And so that can be useful if you want something happening on a recurring basis. But another thing you might notice about all of the JavaScript web pages that we've had so far is that they aren't able to remember anything. If I'm looking at my website right now, it's counting 23, 24, 25, and it's continuing counting. But if it gets to 28, and I close the page, and then I open interval.html again, for instance, now I'm back to zero. It reset the entire page because all of that updating of the variables gets lost when I close that page. So what are some ways that I can get around that and actually store information such that if I close the page and open a page later on today or in the next day, that I can still retain some information, some memory of some state? In order to do that, we'll use a feature of JavaScript that many modern web browsers support called local storage, which allows us to store things inside of the local machine such that even if I close the page and reload the page later, I still have access to that same local storage. So let's take a look now at storage.html. So storage has a counter and a button that says Click Here, much like the examples we've seen that are counting before. And what's happening inside of it? And the first thing I'm doing is I'm doing localStorage.getItem, counter. So localStorage is just a variable I have access to. And it has two functions that I'm likely going to want to use-- getItem, which tries to get an item for me from local storage; and setItem, which sets the value of something in local storage. And so I'm trying to get the item called counter. And exclamation point just means "not." So if not getItem counter-- in other words, there was nothing called counter-- I'm going to setItem, localStorage, set it equal to 0. So I'm setting counter equal to 0. And now what I'm going to do is initially set the counter's inner HTML to be whatever the value of the counter variable in localStorage is. So if localStorage starts off at zero, then the counter is going to initially display 0. But if it's something else, it's going to display something else. And now every time this button is clicked, querySelector button onclick, what am I going to do? Well, instead of setting the variable counter to be zero at first, let's set counter to be whatever localStorage's counter is. Then I'm going to increment the variable counter. counter++. Then I'm going to set the inner HTML of my counter heading to be whatever that counter variable was. And then I'm going to setItem-- localStorage.setItem. Set the value of counter to be whatever my variable counter is equal to. And you could get around this without even needing the counter variable, but I'm including all the steps here just to be explicit about it. And so what's the result of this? This local storage is a variable I have access to. Or it's storage that I have access to even when I close the page and reopen it. So if I open up storage.html here-- and I have this button that will keep counting. And I count up to five, for example, or six, seven, eight, nine, if I now close this page, in the examples we've seen before, it would reset back to zero when I opened the page. But now when I open the page, I'm back at nine. It's retrieved that value from localStorage, and it's using it, and now I can continue to click and continue to update the value of the variable in localStorage. Yeah? AUDIENCE: So the localStorage is storing it in Chrome? SPEAKER 1: Yeah, the browsers need to support localStorage, and so Chrome happens to be a browser that allows us to store information locally within Chrome. And most other modern web browsers will also support localStorage now as well. AUDIENCE: [INAUDIBLE] SPEAKER 1: Yep, it will continue to persist. And so it's a nice way of being able to store data locally such that you can reference it later in future uses. And you may find this proves useful in future projects. AUDIENCE: [INAUDIBLE] SPEAKER 1: Repeat that. AUDIENCE: [INAUDIBLE] SPEAKER 1: You can think of it as-- so a cookie-- so the question is the relationship between this and a cookie. So a cookie would be with regards to interactions with some kind of server, that a server might use a cookie in order to remember a particular user. With regards to this storage website, there is no server involved. It is just data that is being stored on the computer. But it's got some similar elements in spirit. Yeah? AUDIENCE: How do you avoid [INAUDIBLE] collisions? Because you just said [INAUDIBLE] that somebody could use counter in their web page? SPEAKER 1: Great question. So the question is, how do you avoid namespace collisions? What if someone else is also using a localStorage variable named counter? The way localStorage works is that it is reserved for a particular domain name. And so if your website, at one domain name, is using a particular variable in localStorage and some other website at a different domain is using a variable in localStorage, those names will not conflict with each other. But if you, on your domain on two different pages, for example, are using localStorage, those will be the same values for localStorage. And so it would be your responsibility then to make sure that those names don't conflict with each other. Yup. AUDIENCE: [INAUDIBLE] SPEAKER 1: It's still going to be 18. Yeah. OK. So those were some other features of JavaScript-- the intervals and localStorage. What we're now going to take a look at is taking a step back to our world of Flask and Python, and looking at how we can develop applications using Flask that are able to take advantage of JavaScript to do interesting things. And so in order to do this, we are going to introduce the concept of Ajax, which stands for Asynchronous JavaScript and XML, which you can just think of as a technology that we can use in order to get more information from a server even without needing to reload an entire new page. So if we need to get information from some website or some web server, and incorporate it into the page that we're already on without reloading a new page, we can use Ajax in order to do that. And we'll see an example of that right now. So what I'm going to go do is go into the Currency example. And Currency is a Flask program. So if I take this URL and go here-- we saw in previous examples in past weeks how we were able to use the Currency API on fixer.io to get at exchange rates between different currencies. And we saw a command-line program that allowed us to do that. Now we're taking this application to the internet. What I have is a page that just gives me a text field to type in a currency and a button that says Get Exchange Rate. And so if I type in "euro," for example, and click Get Exchange Rate, without any new page-- I didn't go to any new page-- it just tells me, 1 US dollar is equal to this many euros. And if I do Japanese yen, then I get one US dollar is equal to 105.65 Japanese yen. And it's not the case that when I loaded this page I needed to load all of the different currency exchange rates in order to load this page. What's happening, as we'll soon see, is that when I type "Great British pounds," for example, when I click the Get Exchange Rate, I'm making an Ajax request. I'm making another request to my web server, my Flask web server, which is going to get the exchange rate for the Great British pound, give it back to me, and then I'm using JavaScript to update the DOM in order to render this new content. And so we'll take a look at how all of that actually works. So let's take a look at application.pi inside of this Currency application. Inside of this default route, I'm just returning an index.html template-- same as the Flask programs we've seen before. And I also have a route called /convert, which takes the request method of POST-- and this is going to be the route that I'm going to use when I need to get a currency exchange rate. And so what's happening inside of this convert function? Well, I'm first going to get at the data that's associated with this form submission, in particular getting at whatever the value of a currency form attribute is, and save that inside of a variable called currency. And then I'm going to make an API call to the API, passing in US dollars and the currency that I want to convert to. And you can take a look at the examples from past weeks when we were dealing with APIs last time in order to see in more detail how this API works. It's exactly the same thing. I'm just now doing it inside of a Flask application instead of inside of a command-line application. And so I'm going to request that new exchange rate. If, for some reason, the response for that wasn't successful, the status code was not 200, then I'm going to return a JSON object that just says, success false, this request was not successful. And I want to let my client know that, let them know that, for some reason, this request was not successful. Then I'm going to get the JSON data from that request response and check to make sure that the currency is actually in that response. And this just has to do with the way that the API is structured. So this code is going to vary depending on what API you're using. But the way this API happens to work is that I need to check to make sure that the currency is inside of my list of the rates that came back to me. And if, for some reason, that currency wasn't in the list of rates that came back to me, then I'm going to return success is false as well. But if none of that was true-- if the status code was 200 and the currency is inside the data that came back to me-- then I'm going to return this JSON object-- success was true and the rate is whatever data rates' currency is. And if you recall from last time, this is how we extracted the actual exchange rate. And so the long story short of what the convert route is doing is if I provide, as input to this route, a currency value, like Japanese yen or euro, then it's going to make an API request to our currency converter API, and then return back to me, ideally, a JSON object telling me that the request was successful and also giving me back a number representing that exchange rate. It's not giving me back a full HTML page. You can think of this like an API route that's just giving back to me a JSON object, telling me whether the request was successful or not, and telling me what the actual exchange rate is. And I'm going to use that route now inside of my application. So what's inside of my application? Well, inside of index.html, I have a script tag where I'm including this index.js JavaScript file. And this URL for static is just Flask's way of incorporating static files. We've seen a couple examples of this in prior weeks. And inside the body of this page, I have a form where I can type in a currency and click a Submit button. And then I have this div down here, just a section of the website whose ID is result. This is where I'm going to put the result of the computation. But to begin with, I haven't requested a currency yet. So that result field is blank. There's nothing there just yet. And so all of the logic for what's actually going to happen is going to happen inside of index.js. And so let's take a look at that now and see what's happening. So when the DOM content is done being loaded, here's the code that's going to run. What I want to happen is I only need to make some sort of interesting request when someone submits the form. When they click Get the Exchange Rate, then I want to do something. So I select for the form, the thing that has ID form. And when it is submitted, I'm going to run this function. What's happening inside of this function? Well, I'm going to define a variable called request, which is a new XML HTTP request. This is just an object that I'm creating in JavaScript that is going to allow me to make an Ajax request, that's going to allow me to make an HTTP request to some other web server in order to get some information. So then I'm going to define a variable called currency, which is going to be whatever the current value of the Currency input field is. Currency, again, is that text input field. Getting at its value will just get me whatever it is the user typed in-- either euros, or pounds, or whatever the currency might be. And so I now have this variable request that is going to represent a way to make new requests to other websites, much like the request library in Python does, although perhaps a little more wordy, as we'll soon see. And I have a variable called currency that is that currency. And now I'm going to say, request.open, meaning, initialize a new request. It's going to be a POST request, because my route accepts the request method POST. And where am I going to request this to? I need to provide the URL. And I'm going to hit the route /convert. And that's taken straight from application.pi, where we defined a route called /convert and said that it accepts request methods of POST. So what happens next? Well, now I need to tell my request, what should you do when you're done being loaded? In other words, when the request is done, what should happen? And so here's what's happening here. I'm taking my request variable and setting its onload attribute. Again, when it's done being loaded-- in other words, when the request is done-- here's the function that should run. And I'm creating a variable called data. And what should data be equal to? Well, ideally, I want data to be equal to that JSON object that got returned to me when I made a request of a /convert route. All I have, though, is this request variable. So what you'll learn is that request.responseText is an attribute of request that I can use to get the text of the response, whatever the text that came back to me when I made the request was. And JSON.parse is a built-in function in JavaScript that takes that text and tries to parse it as a JSON object that lets me access it using keys and values, like we saw in the API lecture last week. So now I have this data variable that should be equal to whatever came back to me from that /convert route. And if you remember, the /convert route did a couple things. If the request was successful, then the success key in the JSON object was true. Otherwise, that success key was false. And so here, I'm checking for that. If data.success-- in other words, if the request was successful, meaning that success attribute of my JSON object had a value of true-- then here's what should happen. Well, I'm defining the new variable, contents. The contents of my result div should be 1 US dollar is equal to-- and then I want to specify what the exchange rate actually is. And remember, the exchange rate came back to me in this request. It came back in the response text of the request, which I then converted into this JSON data value. And to get at the rate from that data value, I do data.rate. And so 1 US dollar is equal to, plug in the rate here, and then plug in the name of the currency, where that currency was defined in a variable up above, just drawn from whatever it is the user typed in to that input field. And so this is going to be what I want to fill in to that result field inside of my HTML page. And so now I say, we'll get at that result div and update the inner HTML to be whatever those contents were. And so that, if the request was successful, has the effect of providing, inside that result div, the actual contents that I care about. And then finally, else. If the request was not successful, then I just want to set the inner HTML to be, there was an error just to indicate that something went wrong. Any ideas on what's missing from the request? Not from the onload function. But so far, I've created a request. I said, I want that request to be POST request that goes through /convert. And this is the code that should run when the request is done being loaded. What information have I not yet included or used? Yeah? AUDIENCE: I didn't see your URL. SPEAKER 1: The URL is there. So if you would look a little higher, I specify when I initialized the request in request.open, we're going to make a POST request to the /convert route or URL. But what's still missing? Any thoughts? So I'm making a POST request to /convert, which is going to try and do some currency conversion for me and find the exchange rate between US dollars and some other exchange rate. But I haven't yet actually told this request about the currency that I want information about I haven't told this request, look up the exchange rate for euros yet. I've just used this variable currency so far just inside this contents of what should be displayed on the page, but I haven't sent that information to the server yet. So I need some way of taking that currency and putting it inside of the form data that I want to send to the server. And so in order to do that, what I'm going to do is create a new variable called data, which is going to be equal to a new form data object, which is going to hold the form data. And I'm going to add to this data, using data.append, a key called currency, whose value is the currency variable that I defined up above, that currency variable that was the name of the currency. Finally, finally, I do request.send, and I send this data along with it. I want to send a request to the /convert route, but I want to pass in the data about what currency I actually care about converting to. And then return false just stops the page from reloading after I submit the form. And so high-level overview of all of this. And the source code we made available afterwards if you want to take a closer look at it. We create a new request; tell it where to request to, the /convert route; tell it what to do when the request is done, getting at that JSON data and doing something with that data; then finally, specifying what information should be included with the submission of the form; and then finally, actually making the request down here. And so the result of all of that is that I can type in something like "euro" and get the exchange rate for a euro. And if I type in a currency that doesn't exist and try and get the exchange rate, I get "There was an error" coming back to me all on the same page, all by making Ajax requests that, without needing to reload the page, allow me to get additional information. Yeah. AUDIENCE: [INAUDIBLE] SPEAKER 1: Great question. So the question is, could I have instead just set up an Ajax request that was directly accessing the currency? Absolutely. You could have just requested the API directly and parsed that JSON response, but this was just meant to be an example of how you can use a Flask server back end if you have your own data that you want to process in some way in order to return. But yeah, good question. All right. We'll take a look at one other feature of JavaScript that web browsers now support that will be powerful as we begin to develop more sophisticated web pages. And that is a feature known as web sockets. And so normally when we think about making web page requests on the internet between clients and servers, we think of it in terms of the request response model, where I, on my computer, make an HTTP request to some web server requesting for some information, and then that server gives back to me some response. And that's useful so long as any time I need data, it's only because I'm requesting that data first and then I get back that response. But what you'll soon see is that in Project 2, which we'll release later today, what you're going to be building is a chat room-style application, kind of like Slack that we've been using in the class. And what that will mean is that it's not really going to be the case that if someone sends a message via some chat room, that you're not going to want to refresh your page in order to request any new messages and then get those messages. What you want is real-time communication, where your client and server can both be talking to each other simultaneously, or what's called full-duplex communication. And to do that, modern web browsers support what are called web sockets, which allow for a protocol that allow for that full-duplex communication between client and server simultaneously that allow for more real-time communication between the client and server. And Socket.IO happens to be one example of a JavaScript library that lets us do things like this. So we'll take a look at some examples of that in order to show you how this can work and how it can ultimately be powerful. And so what we're going to do is build an application that allows different people on different pages to cast votes for something. They can vote yes on a motion or on a bill, or they can vote no, and they can vote maybe-- is what we're going to try and do. And ultimately, we're trying to build out an application that lets anyone logging in see the results of this voting. Lets anyone see whenever someone else votes in real time. So let's take a look now at vote0application.pi. And so what's going to happen here is I am going to define, inside of my index function, the route. I'm going to return the index.html page. And what I'm going to use is a library called Flask Socket.IO, which is going to allow me to use web sockets inside of a Flask application. And you'll see how all this works in just a moment. But the idea of it is going to be that my web server and my web client are going to be sending events, or emitting events, that are broadcasted to everyone else; and they're going to be listening for events, receiving those web socket events; and doing something interesting with those events. And let's take a look at just some of this code and then get a sense for what's happening. If we go to vote0index.html, what we see is inside of index.html, it's pretty simple. I'm including an index.js JavaScript file, which we'll soon see at work in just a moment. And inside the body of this application, I have an unordered list that's going to keep track of all the different votes that people have cast. And then three buttons-- a Yes button, a No button, and a Maybe button. And notice, in particular, that each one of these buttons has a date-of-vote attribute, where date-of-vote is just me giving additional information to these buttons such that, in JavaScript, I can extract this data out of it. And so I have a data vote that's equal to yes, one that's equal to no, and one that's equal to maybe. And so the interesting stuff is all going to happen inside of index.js. And so what's happening here? Well, when the web page is done loading, the first thing I need to do is connect to the web socket to allow for this communication in real time between the client and the server. And so this is just a standard line that Socket.IO will use. We'll connect to location.protocol, which will be either HTTP or HTTPS, most likely, plus the domain name, and then whatever port you're currently working on. So you can sort of just copy this line and treat it as, this is what's going to allow me to connect to this web socket implementation. And now these web sockets can listen for particular events. And so in this case, what I want to do is once the web socket is connected, I want to make sure all of my buttons are configured to do something with the web socket. In particular, when the button is clicked, I want to emit a new event, telling the world, or telling my web server in particular, that a vote has been submitted. So how am I going to do that? Well, once the web socket is connected, here is the code that I want to run. I'm going to do a querySelectorAll, selecting all of my buttons. And for each one of those buttons, here is the code that I want to run. When that button is clicked, I'm going to run this function. And that function is going to define a variable called selection, which is equal to whatever the button's data-vote attribute is. Remember, data-set gives me access to all the data attributes of the HTML element. And so each of my buttons had a different data-vote attribute-- either yes, or no, or maybe. And I'm going to save that in a variable called selection. And now I'm going to run this code, which is the interesting code. socket.emit is going to emit this event to my web server in order to notify my web server of this new event. I'm giving the event a name. I'm just going to call it submit vote. And then I'm passing in the data that is associated with that event. In this case, it's just a JSON object that contains a key called selection. And its value is whatever it is that I actually selected-- either yes, or no, or maybe. So what this code will ultimately do is that once my web sockets are configured and connected, when I click on a button-- either yes, or no, or maybe-- it's going to figure out which button did I click on, and save that in a variable called selection. And then it's going to emit an event to my web server. That event is called submit vote. And I'm passing in that selection data as part of it. And so now before I go on to what's actually happening later on in this JavaScript code, let's go back to the web server code. So to draw the distinction, remember, this JavaScript code is code that's happening on the user's own machine-- locally on their computer. And here in application.pi is the code that's running on our Flask server. And so down here, we have this special syntax-- socket.io.onsubmitvote. So this is my way of saying, when the socket detects this event, an event called submit vote, and recalled it in the JavaScript-- when we emitted the event, we named the event submit vote. So that's going to connect it to this particular function. So when someone submits the submit vote event, here's what you should do. First, take the data and get at the selection, because that was the data that was passed in via this event. And save it inside of a variable called selection. And so now if we think about this in terms of making sure all of our computers know about what vote has been cast, if one computer casts a yes vote and says, I've submitted a vote, submit vote event, tell the server that I've cast a yes vote. And I now get this notification, effectively, that a yes vote has been cast. The next step for me is going to be to tell-- to broadcast to everyone else-- that yes, a submit vote has just been cast, and that vote was a yes vote. And so that's what this emit function is doing. And you can import it from Socket.IO up above. And I'm emitting a new event called announce vote. And I can also pass in data to it. And I'm announcing that the selection is the selection. And this is going to announce it to any other sockets that are listening, not just the original user. And so I've saved the selection, I'm emitting a new event called announce vote, its selection is equal to whatever the selection was. And broadcast equals true means I want to broadcast it to everyone, including the person who originally cast the vote, because they should theoretically know about it as well. So I've emitted this announce vote. And so now back on the client side, back inside the JavaScript, to continue this story, what's going to happen is that I'm going to tell the socket, when you receive an announce vote signal, this is what you should now do. Run this function that takes, as input, the data. We're going to create a new list item, just like we did before using document.createElement. The inner HTML of that list item is going to be Vote recorded followed by whatever the selection was, whatever it is that they actually voted for. And then I'm going to append this list item to #votes, that list of votes that I've been accumulating. So to tell the story very briefly one more time, when I first connect the sockets, I set it up such that whenever a button is clicked, I emit a submit vote event, telling the server that a vote has been submitted. On my server now, when I receive this submit vote event, I check what the selection is, and I broadcast to everyone this announce vote event, telling people that a vote has been made, and I want to announce it to everyone. And in everyone's index.js file now, when they receive this announce vote event, they're going to run this function, which is going to add to my list of votes, telling everyone what that vote is. So if I now go into vote0 and do Flask run, I'm going to go to this URL. And what I'm actually going to do is I'm going to open up this URL twice. I'm going to open it up in two different windows. So you can think of this as two different users that are both using the system. They both have a yes, no, and maybe vote. And so when I click on this Yes button, what ultimately happens is-- oh, sorry, refresh these. When I click on the Yes button, it says, "Vote recorded-- yes." And so how did that appear on both of them? Well, on one side, I clicked the Yes button. That sends the announcement up to the server that I've submitted the yes vote. And then the other person, without needing to refresh their page or reload anything, is notified, because the web server that announces, or emits, and broadcasts to everyone that a new vote has been cast. So I can cast Yes vote, No vote, Maybe vote. And it updates for all of the users that are connected to this socket. And likewise on this side, I can also cast votes, and it will appear on the first side as well. And so this is Socket.IO in action. And as you begin to develop your chat application, you can see how this would be useful-- that when someone sends a message and presses Return, the other person can see that message immediately without needing to wait a couple seconds, and refresh the page, or do something else in order to see the results of that. We'll take a look at one other example of this, of just Socket.IO in action, in terms of how this casting of votes and how the emitting of events on the client and server work. An improvement to this vote application would likely be that I don't really care about seeing this hierarchical list of votes. What I really care about is seeing the vote totals. I want to know how many yes votes are there, how many not votes are there, how many maybe votes are there. And in particular, one other drawback of the approach we have right here is that if I ever close one of these windows and then open it again, well, now all the votes are gone. Like, on this side, I don't see any votes. And if I say no on this side, we'll now know it appears over here. But because, by default, my page loads with an empty list, I didn't get all that history of all of the previous votes that had been submitted. So I need some way of storing that information such that, when future people visit the website later, they can see that information as well. So let's take a look now at vote1. And inside of application.pi for vote1, we're going to maintain one thing. I have here a variable, just a global variable, inside of Flask's memory that's going to just store information, store information that any client connecting to my Flask server is going to be able to take advantage of. And this is just going to be a dictionary that stores the current vote counts. Currently, yes's have zero votes, no's have zero votes, maybes have zero votes. And when I go to the default route, just go to the index page, I'm going to return index.html, passing in that votes variable, because I want my index.html template to know what the initial vote counts are. They start out at zero, but maybe by the time that I get to the website, different people have made different votes, and I want to know what those current vote tallies are. So if I go to index.html now, what I see inside my body is three divs, one that says Yes votes. And then I have a span. Recall that a span is just a segment on my HTML page that I can give attributes, like a name, or an ID in this case. And I'm giving this one an ID of yes, because later on, I want to fill something in to that spot. But we'll see that in just a moment. And that is going to be set to whatever votes yes is, the Yes field of that votes object that I passed in. And likewise, I'm doing the same for displaying the current number of no votes and the current number of maybe votes. And then these buttons are the same as well. So what's happening now inside of index.js? Well, this is mostly the same. When I submit a vote, this is identical. When I click on a button, I want to figure out what vote am I voting for and then emit this submit vote event, passing in that selection. What changes is what happens on the server side. So what do I want to happen when a vote is submitted? Well, when a vote is submitted, I still want to get the selection of data.selection. But rather than just emit it right away, I want to store it in memory. I want to make sure my application knows what the vote total is, so that the next time that a user comes to the site, they're informed of that latest vote total. And so I want to update this Votes dictionary that's keeping track of yes, and no, and maybe votes. And to do that, I'm doing votes to access this variable. In square brackets, selection, where selection is going to be one of yes, or no, or maybe. And then plus equals 1, just to say, increment that total. Increment either yes, or no, or maybe to be one larger than it was to indicate that I now have one more vote. And then finally, down here, I'm going to emit a new event called vote totals and pass in this votes variable here, which is just this Python dictionary that contains all of those vote totals. That's the data that I want to send to all my clients. That's the data that I want to broadcast for everyone to know about such that now, if we go back to the client side of things on my computer, what should happen when I get this vote total event? Well, I want to update my yes span, the thing that has ID yes, set its inner HTML to be whatever data.yes is, and likewise with no and maybe, such that when I get the new vote totals back, I want to update my current counts of what all the votes are. And so the result of this, if I go in to vote one and do Flask run-- and I'll open it twice for good measure. I now see yes, no, and maybe votes, and three buttons at the bottom. And when I click Yes, for example, on one of them, the vote tally updates on both my computer and presumably someone else's computer that is also connected by web sockets to the same web server. And clicking on any of these individual buttons will result in updating that. And unlike last time, where if I closed the window and then reopened it, it reset back to the original state, because I'm saving this information inside of Flask's memory, in server-side memory in my Flask application, when I go back to this site now, I see the same vote totals, because it's able to take that information, pass it into the index.html template, and now allow me to continue voting just as I was able to before. So that's Socket.IO in action. Ultimately acts as a way to allow for this real-time communication and will likely prove helpful to you in Project 2 as you begin to dive deeper into Python, and Flask, and JavaScript, and sockets in particular in order to build these increasingly more and more dynamic web applications that include client-side code that's really running on the inside of the browser inside of the client's computer. And all of this is just a taste of what JavaScript is really capable of. We've just seen a couple of the features of DOM manipulation, and sockets, and other features. But JavaScript can do a whole lot more, as we'll begin to look into in future weeks. But for now, that's it for JavaScript for today. And best of luck with Project 2.
Info
Channel: CS50
Views: 84,544
Rating: undefined out of 5
Keywords: cs50, harvard, computer, science, david, j., malan
Id: xMs4ER1rcLg
Channel Id: undefined
Length: 107min 5sec (6425 seconds)
Published: Tue Mar 06 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.