[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.