Page 3: HTML and JavaScript

CS559 Spring 2022 Sample Solution

On the Previous page we made simple web pages, here we’ll see how to put JavaScript programs on them.

JavaScript can be tricky to learn because not only must you learn a new language, but usually the programming happens in the context of a web page in a web browser.

The Javascript in CS559 has all sorts of resources about JavaScript, including the rationale for why we are using it in class. If you are already a JavaScript expert, that page will tell you some rules for how we use JavaScript in class. If you are just learning JavaScript, the page has links to some good tutorials. You will also be able to figure a lot out from the examples we provide in the workbooks.

The goal of this page is to help you understand where JavaScript programs go, when they run, and how they work with the workbooks. If anything is too unfamiliar, you might want to review some of the Javascript resources on the Javascript in CS559 page.

Box 1: Where does my code go?

Here is a miniature web page 01-03-01.html. It’s boring but it does have a little program in it.

The output of this program, from the console.log function, will be in the “console” of your web browser. Now is a good time to look for it (it should say “Box 1’s initial message to the console”, but you’ll also see the output from box 3 and 4). You might try opening the box as a separate web page (here’s a link). See what the console shows for this.

If you’re not familiar with the console, now is a good time to find it and try it out. You can type JavaScript into the console to try things out. To open the console in Chrome and Firefox on Windows machines it is typically CTRL-SHIFT-I (the letter I). The console is also important because it’s where compilation and runtime errors are displayed. Make sure you understand how to access the console and what gets printed to it.

Box 2: Another place to put code

When you make a button (or other element), you can attach code to it right in place, as in this example (again, look at the console and the code). Since this is the second box,

In general, we prefer not to put much code hidden inside of the html. It’s fine for short things, but when the code gets complicated (as it will), it’s easier to have it in a separate file.

Just to make sure you’re reading along, change this box so that when you press the button, the message in the console is a grammatically complete sentence like “Button one was pressed.” (yes, there are points on the rubric for this).

Box 01-03-02 Rubric (2 points total)
Points (2):
Box 01-03-02
2 pt
change text on button press

Box 3: Where to put code

If we’re not supposed to put JavaScript into the HTML files, the next question is where to put it.

We will put JavaScript programs into separate files - dividing them up into smaller chunks (roughly “modules”), but that will come later. By convention, I will always name my JavaScript files with ‘.js’, although other people will do other things (for example, we might name the files with ‘.es6’ to signify that we’re using the ES6 version of JavaScript).

Here’s another simple example:

For something this simple, having things split between 01-03-03.html and 01-03-03.js may not be a big deal, but its a good habit to get into.

If you’re curious (and you should be) the type="module" in the <script> tag tells the browser that we want the “modern” version of JavaScript, and that we want to treat the file as a separate module. You can see the explanation in the HTML documentation for the script tag, but, basically for class we’ll always use it.

Box 4: When to run code

There is a question of when those little snippets of code get run. In some cases, it’s simple: for the button in Box 2, we assigned code to the onclick event of the button, so the code was run when this even happened (we’ll discuss events more later). But, for the code in the script tags (especially when the script tag loads another file), the code will be executed when the script tag is processed. This becomes even more complicated because the web browser can do things asynchronously - it doesn’t wait until the first thing finishes before starting the second. This creates a potential problem: we want our JavaScript program to access our web page, but we don’t know if the web page has finished loaded (and is ready to be accessed) when our program is run.

If you look at 01-03-04.html, you will see that the html file specified loading the script first and then provides the html elements that the script refers to. We use the defer option to make sure that the script is executed after the page is done loading. Defer is the default for module loading. In the past, we had to do more complicated things to make sure the script didn’t run until the page is done loading.

Normally, a script tag that loads a file, such as <script src="01-03-03.js"></script>, gives the browser some flexibility in when it chooses to run the script. However, we can add the defer flag like this: <script src="01-03-03.js" defer></script> which tells the browser to run the script only after the page has finished loading. This is explained on the W3 Schools documentation on defer and Office Script Tag Documentation.

01-03-04.html below gives an example of defer being used. Try removing it (you need to remove the defer and the type="module" and see what happens (you will get an error, because 01-03-04.js can’t find the paragraph element it’s looking for). The error isn’t reliable: sometimes (because of asynchronous browser execution), the page will finish loading before the script executes (since the script is delayed while it gets read in). To make things reliable and predictable, we will just always use defer in class.

Functional Programming, Javascript, and CS559

We are introducing functional programming concepts early on, and will make a big deal about them. This is partially because they are a nice feature of Javascript. Historically, they were the flexible building block that were used before Javascript had other features.

But, the big reason for emphasizing them early in the class is that they really are a convenient way to do graphics programming. They will come up a lot in the programming we do for class. So, it’s good to get familiar with them now.

To help you learn about these things, there is an optional workbook: Closures Workbook. You can clone the repository and work through the examples, or you can just read the tutorial on the web. There is also a video lecture Closure Tutorial Video, and the associated slides here.

You should expect questions on functional programming concepts (like closures) on the exams.

Part of the reason for this is that we like to (or, as we will see on the next page, are often forced to) think about out programs in terms of functions that get called when events happen. In the examples so far, we had functions that executed when a button was pressed or when the page finished loading - each of these are events.

It’s worth looking at a simple example before we move on… Here is Box 01-03-02, re-written to put the script in a different place.

This is now example 01-03-05.html. Let’s look at the key lines…

15
16
17
18
let button = document.getElementById("button1");
button.onclick = function() {
    console.log("Button 1 Pressed!");
}

Line 15 finds the button by searching for an HTML element on the page with the name button1. Good programming practice would have checked that button was actually found. We’ll do this often - we find objects on the web page by ID and do things to them.

The more interesting thing is what we do to the button: we assign something to its onclick property. This stores a function that gets called when the button is pressed. But notice that we put the definition right in the assignment. We are defining the function in place. You can think of the function keyword not just as defining a function, but as effectively running the compiler and producing a “function object” that can be stored in an attribute of the button (or any other variable).

Effectively, the code inside the braces on lines 16-18 doesn’t get compiled until the function expression is executed. Line 17 doesn’t get executed when this code is run - it just gets fed to the compiler. The output of the compiler - which is a “function object” - can be produced and stored somewhere, and called later.

(note: this idea of “running the compiler” is a simplification of what really happens in order to give you a mental model of how things work)

The fact that we’re effectively running the compiler as our code runs brings up interesting possibilities. We can define new functions as our program is running, and those functions have access to the current state of the program.

Here’s a slightly different example…

You can see this in 01-03-06.html. The code is a little different…

13
14
15
16
17
18
let number = 1;
let button = document.getElementById("button1");
button.onclick = function() {
    console.log(`Button ${number} Pressed!`);
}
number = 2;

The first difference you may notice is line 16 - rather than printing a normal string, I am printing a string with a variable in it. The back ticks “`” tell Javascript that this is a template literal - a cool javascript feature that lets me access data within a string. You can read the Template Literals Documentation to find out about them (recommended, they are quite useful). However, for now, trust me that what this does is print the value of the variable number in the middle of the string.

So, the big question… what is the value of this variable?

A thing to notice is that the variable number is declared outside of the function we are creating. When we “compile” the function, the variables that enclose the function (defined outside, but available inside) are kept. This is called closure - it is a fundamental functional programming concept. It is tricky to learn. Most students have to hear it several times before they get it. I will explain it multiple times during class. There will (almost certainly) be exam questions involving closure.

Consider what happens with this program. When the code is executed, function calls the compiler. At this point, the variable number is 1. However, line 16 doesn’t execute - it is just compiled. It keeps a reference to the variable number. This is closure. After the compiler is done creating the function number is set to 2. Later on, when the button is pressed, the function is executed. At this time, it refers to the number, which has value 2.

That’s a closure. It lets functions access data defined outside. We’ll see a lot more examples. Don’t worry if you don’t get it the first time.

If you would like more explanation now, see this video Closure Tutorial Video, and the associated slides here.

Moving On…

So now we’ve seen where code can go and how functional programming lets us define the functions we can put in various places. Now let’s see how to make it do something useful on the Next Page

Next: Doing things to HTML