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