"Gots and Needs" Notecards

On one side of the notecard, write what you feel like you've "got" regarding JavaScript this week.

On the other side of the notecard, write 1-2 things you feel you still need to understand, or that would help you understand this material (update if it was covered by end of lecture!)

CSE 154

Lecture 8: JS with the Document Object Model (DOM) and UI Events

Today's Agenda

  • Administrivia:
    • Exploration Session on Bootstrap and Other CSS Tricks tomorrow (4:30PM at MGH 389)
  • Modular JavaScript with HTML/CSS
  • Case Study: Connecting JS to HTML/CSS with DOM/Events

Unobtrusive JavaScript

Recall our goal was to keep our web site code "modular" and separated into 3 major categories:

  • content (HTML) - what is it?
  • presentation (CSS) - how does it look?
  • behavior (JavaScript) - how does it respond to user interaction?

What does this mean?

  • HTML with a link to a JavaScript file (in the module pattern) with no JavaScript code inside the <script> tags
  • Initialize your JS with a window load event handler
  • Use the JS and DOM to attach and execute all JavaScript event handlers

JavaScript File Skeleton

/**
 * Name, section, date, etc.
 * Description of program
 */
(function() {
  "use strict";

  // any module-global variables/constants

  window.addEventListener("load", init);

  // phew! your functions goes here

})();

JS

Reference template here!

A Note about JavaScript "strict" mode

"use strict";

...your code...

JS

Writing "use strict"; at the very top of your JS file turns on strict syntax checking:

  • Shows an error if you try to assign to an undeclared variable
  • Stops you from overwriting key JS system libraries
  • Forbids some unsafe or error-prone language features

You should always turn on strict mode for your code in this class!

Check Your Understanding

Page Event Flow Exercise: JS Source Code and linked HTML

So, when does my code run?

<html>
  <head>
    <script src="ex1.js"></script>
  </head>
  <body> ... </body>
</html>

HTML

let x = 3;
function f(n) { return n + 1; }
function g(n) { return n - 1; }
x = f(x);

ex1.js -- JavaScript

Your file's JS code runs the moment the browser loads the script tag

  • Any variables are declared immediately
  • Any functions are declared but not called, unless your global code explicitly calls them

Important! At this point in time, the browser has not yet read your page's body

  • None of the DOM objects for tags on the page have been created yet

A failed attempt at being unobtrusive

The following example does factor out JS code into a .js file, linked from ex1.html. But what's wrong with it?

<html>
  <head>
    <script src="ex1-bad.js"></script>
  </head>
  <body>
    <button id="my-btn">Click me!</button>
  </body>
</html>

ex1.html

let btn = document.getElementById("my-btn");
btn.addEventListener("click", responseFunction);

function responseFunction() {
  console.log("Hi!");
}

ex1-bad.js

Problem with Example Code

let btn = document.getElementById("my-btn");
// this is bad: btn is null at this point
btn.addEventListener("click", responseFunction);

function responseFunction() {
  console.log("Hi!");
}

Script in head is processed before page's body has loaded

No elements are available yet or can be accessed yet via the DOM

This problem is solved by attaching a function to the global window load event, which fires once everything in the page has been loaded.

Solution: ex1-good.js (this one doesn't use the module pattern though, so it's not best!)

Thinking about Page Behavior

There are different types of behaviors on a page. But when you're first learning JavaScript, it may seem like there are a ton of different things to keep track of, and connecting the dots can be tricky when staring at code.

But it's really not that complicated if you break it down before starting the code.

What's involved in a page event?

source.addEventListener("event", response);

function response() {
  // response behavior with possible output/document elements changed
}
  1. The source listening to the event. Most sources of an event will be document elements (a button, a dropdown, paragraph, etc.) but you can also have the window as a source to listen (always for the load event, sometimes for various key events like keyPress).
  2. The event listened to by a soure object (e.g. click, load, mouseover, keypress).
  3. The response for the event
  4. The output/elements changed in the response

Another Event Handler Binding (mouseover)

window.addEventListener("load", init);

// called when the window's load event is fired and we have access
// to elements on the DOM
function init() {
  let msgP = document.getElementById("msgP");
  msgP.addEventListener("mouseover", showMsg);
}

function showMsg() {
  this.innerText = "You moved the mouse over me!";
  // same as document.getElementById("msgP").innerText = "...";
}

JS

Event handlers attached unobtrusively are bound to the element

Inside the handler, that bound element becomes this

Extra Practice (At Home)

The following worksheet/code is another example we used in a previous quarter. We have provided it as an extra resource to work through at home to solidify your understanding of event flow!

Practice Worksheet (Key)

Running HTML and JS Implementation (with comments!)

Remember Friday?

We introduced different form element tags offered in HTML

But they're not too helpful if we can't do anything with them!

In general, to add interactivity to our HTML/CSS websites we need to:

  1. Link a JS program to our HTML (in the <head>)
  2. Identify user/page events we want to respond to
  3. Identify what each response function is
  4. Get the HTML DOM elements we want to be interactive, and "assign" the element its own event(s) to listen to

Groupizer Demo

Starter HTML/CSS/JS: groupizer-starter.zip

Commented solution for where we left off at the end of lecture: groupizer-v1-solution.zip

The <select> dropdown

Recall the <select> dropdown for choosing the member count in a new group:

<select id="group-size">
  <option>2</option>
  <option selected="selected">3</option>
  <option>4</option>
</select>

groupizer.html

output

Getting a Newly-Selected Group Size

In Groupizer, when a user changes the number of members possible in the new group, we wanted to update the number of inputs for new member names according to the current value.

To get the value of the <select>, you can access its .value attribute, which returns the value of the <option> currently selected.

function init() {
  // ... other setup code
  // the "change" event is fired whenever a user changes the dropdown selection
  id("group-size").addEventListener("change", updateMemberCount);
}

function updateMemberCount() {
  // can use .value on a select element to get currently-selected option 
  let currentCount = id("group-size").value; 
  // ... use currentCount to update number of member name inputs
}

groupizer.js

Extra Resource Slides

Recall the <button>

<button id="my-btn">Click me!</button>

HTML

output

Button's text appears inside tag; can also contain images

To make a responsive button or other UI control:

  1. Choose the control (e.g., button) and event (e.g., mouse click) of interest
  2. Write a JavaScript function to run when the event occurs
  3. Attach the function to the event on the control

So how did that happen?

First you get the button from the HTML Page

To access an element you use document.getElementById

let element = document.getElementById("id");

JS

document.getElementById returns an object for an element with a given uniqute id in the document.

Note that you omit the # when giving an id in JS

Then handle the click event

// attaching a named function
element.addEventListener("click", handleFunction);

function handleFunction() {
  // event handler code
}

JS (click event template)


// (alternative) attaching an "anonymous" function
element.addEventListener("click", function() {
  // event handler code
});

JS (click event template)

JavaScript functions can be set as event handlers

When you interact with the element, the function will execute

So how do I get started with adding interactivity to my page?

Tips for meeting CP2 External Requirements:

  • Add event listener to a source element, and respond
    • What is your source?
    • What is your event(s)?
    • What is the response behavior?
    • What elements change as a result?
  • Add/remove elements in the DOM (you can do this as part of a response function!

Accessing Properties of a DOM object (Example)

<p>See our <a href="sale.html" id="saleslink">Sales</a> today!</p>
<img id="icon" src="images/shop.jpg" alt="Shop Icon" />
<p class="photo user-upload">Beauty.</p>

HTML

let theIcon = document.getElementById("icon");
let theLink = document.getElementById("saleslink");
let paragraphs = document.querySelector("p");

JS

Property Description Example
tagName element's HTML tag icon.tagName is "IMG"
className CSS classes of element caption.className is "photo user-upload"
src URL target of an image icon.src is "images/shop.jpg"
href URL target of a link theLink.href is "sale.html"

Changing Text with innerText

            let paragraph = document.getElementById("welcome");
paragraph.innerText = "text!";

JS

innerText should be used to replace text to a DOM element (can also use textContent, which is another common solution)

Can't add HTML tags this way, but soon, we'll see a better way to add HTML tags to our page.

Summary: What can we do with DOM objects so far?

Set their properties, and the page changes in response

This is how give behavior to web pages: use JavaScript to manipulate the DOM by changing the properties of DOM elements

In the rest of Module 2, we'll learn how to add/remove nodes from the DOM, do more with different types of events, and delay/repeat functions on our page with timers!