CSE 154

Lecture 8: More About Events

What we've Covered in JavaScript so Far

Types (Strings, Numbers, Arrays)

Conditionals, Loops, Functions

Modular JS Pattern

Basic Event Handlers with addEventListener

Basic HTML UI Elements

Today: Page Event Flow and Timers

The Notion of "Objects" in JavaSript

When working with pages, anything you interact with on the page is an "object" (but not in the same definition as Java).

An object in JavaScript has a set of properties (e.g. innerText for DOM objects) and built-in functions (e.g. addEventListener. Some objects have different properties/functions than others.

It is helpful to think of the following "types" of objects in JavaScript (this is informal, but can help you moving forward):

  1. Global DOM objects
  2. Objects inside the document (which is a Global DOM object)
  3. Event objects (yes, events are objects!)

What kinds of properties (information) do you think would be useful to have access to in an page event?

The Six Global DOM Objects

Every JavaScript program can refer to the following global objects:

method description
document current HTML page and its content
history list of pages the user has visited
location URL of the current HTML page
navigator info about the web browser you are using
screen info about the screen area occupied by the browser
window the browser window

You will usually just use window and document.

Recall: How to get DOM elements in JS

  1. Ask for them by id: document.getElementyById(...)
  2. Query for them with CSS style selectors:
    • document.querySelector(...)
    • document.querySelectorAll(...)
  3. Make new ones! document.createElement(...) (introduced soon)

What's inside a DOM object?

For starters, the HTML attributes. This HTML:

<img src="images/puppy.png" alt="A fantastic puppy photo"/>
<p>A paragraph!</p>

HTML

Has two objects (let's call them puppyImg and p) with these properties:

  • puppyImg.src -- set by the browser to images/puppy.png
  • puppyImg.alt -- set by the browser to "A fantastic puppy photo"
  • p.innerText -- set by the browser to "A paragraph!"

Event Objects

Contain properties about an event that occurred.

So, when does my code run?

<html>
  <head>
    <script src="myfile.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);

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

<html>
  <head>
    <script src="myfile.js" type="text/javascript"></script>
  </head>
  <body>
    <div><button id="ok">OK</button></div>
    (... more html ...)
            

HTML

let btn = document.getElementById("ok");
btn.onclick = okayClick;  // this is bad: btn is null at this point
            

myfile.js -- JavaScript

Problem: global JS code runs the moment the script is loaded

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.

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

Worksheet Exercise

Filled out tables

JS Implementation (with comments!)

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

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 a delay or repeated interval for a function response
  • Add/remove elements in the DOM (you can do this as part of a response function!

The Keyword this

this.fieldName                 // access field
this.fieldName = value;        // modify field
this.functionName(parameters); // call method

JS

All JavaScript code actually runs inside of an object

By default, code runs in the global window object (so this === window)

  • All global variables and functions you declare become part of window

The this keyword refers to the current object

For response functions atteched in addEventListener, this refers to the source element of the event.

Event Handler Binding

window.addEventListener("load", initialize);

function initialize() {
  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 = "You moved the mouse over me!";
}

JS (example from worksheet page)

Event handlers attached unobtrusively are bound to the element

Inside the handler, that element becomes this

Optional parameter in Event Handler Functions

The functions we've seen so far to respond to events like click have had the following format:

sourceEl.addEventListener("click", responseFunction);

function responseFunction() {
  //
}

JavaScript gives us a really useful way to get more information about an event that fired the callback function by accepting an optional parameter to the attached function representing the event object.

Conventionally this event object is given the name "e" or "evt"


sourceEl.addEventListener("click", responseFunction);

function responseFunction(e) {
  // each time this line is reached in response to a click, we have a new
  // event object "e" with data about the event (time, location, etc.)
}
          

Back to JS: How an event is handled

<button id="ok">OK</button>   <!-- (1) -->

HTML

window.addEventListener("load", initialize); // (2)

// called when page loads (from event (2))
// sets up event handlers
function initialize() {
  let ok = document.getElementById("ok");    // (3)
  ok.addEventListener("click", okayClick);
}

function okayClick() {
  alert("booyah");                           // (4)
}

JS

Check Your Understanding

let clicks = 0;
window.addEventListener("load", main);

function main() {
  let foo = document.getElementById("foo-btn");
  let bar = document.getElementById("bar-btn");

  foo.addEventListener("click", function() {
    console.log("A button was clicked!");
    clicks++;
  });

  bar.addEventListener("click", function() {
    console.log("A button was clicked!");
    clicks++;
  });
}

JS

  1. What are three "quality" issues you can find in this JS program?
  2. How many global variables/functions (symbols) are there?

Timers

Used to delay or set intervals for executing functions

Setting a Timer

method description
setTimeout(function, delayMS) arranges to call given function after given delay in ms
setInterval(function, delayMS) arranges to call function repeatedly every delayMS ms
clearTimeout(timerID)
clearInterval(timerID)
stops the given timer

Both setTimeout and setInterval return an ID representing the timer

  • This ID can be passed to clearTimeout/Interval later to stop the timer

setTimeout Example

<button id="demo-btn">Click me!</button>
<span id="output-text"></span>

HTML

window.addEventListener("load", function() {
  document.getElementById("demo-btn").onclick = delayedMessage;
});

function delayedMessage() {
  document.getElementById("output-text").innerText = "Wait for it...";
  setTimeout(sayBooyah, 5000);
}

function sayBooyah() { // called when the timer goes off
  document.getElementById("output-text").innerText = "BOOYAH!";
}

JS

output

setInterval Example

let timer = null; // stores ID of interval timer
function delayMsg2() {
  if (timer === null) {
    timer = setInterval(sayHello, 1000);
  } else {
    clearInterval(timer);
    timer = null;
  }
}

function sayHello() {
  document.getElementById("output-text").innerText += "Hello..."
}

JS

output

Passing Parameters to Timers

function delayedMultiply() {
  // 6 and 7 are passed to multiply when timer goes off
  setTimeout(multiply, 2000, 6, 7);
}

function multiply(a, b) {
  alert(a * b);
}

JS

Any parameters after the delay are eventually passed to the timer function

  • Doesn't work in IE; must create an intermediate function to pass the parameters

Why not just write this?

setTimeout(multiply(6 * 7), 2000);

JS

Common Timer Errors

Many students mistakenly write () when passing the function

setTimeout(booyah(), 2000);
setTimeout(booyah, 2000);

setTimeout(multiply(num1 * num2), 2000);
setTimeout(multiply, 2000, num1, num2);

JS

What does it actually do if you have the ()?

  • It calls the function immediately, rather than waiting the 2000ms!

New vs. Old in JavaScript

JavaScript has evolved quite a bit since it was first created.

Why? It was the first real client-side programming language that allowed people to add interactivity to their HTML and CSS pages.

A ton of work has been done to improve standards between browsers and JavaScript, and adapt to an increasingly connected world with different devices and users browsing the web.

As a result, you may see different ways to accomplish something in JS. In this course, we focus on providing a foundational knowledge of JS to implement interactive web pages, while laying a foundation of best practices.

Online Resources: Good or Bad?

You may find some resources online helpful to explore different ways to implement UI's in JavaScript - there are a ton of things! But some are better than others (make sure you understand why these examples are poor use of JS).

For reference, here's a much better solution using what we've taught in this course to accomplish a mouseover demo given by W3Schools (view HTML source to get CSS/JS).

Understanding good code quality can be extremely valuable in navigating an overwhelming amount of resources on the web today.

Understanding the Good vs. Bad

We choose resources that best align with our code quality guidelines, while giving just enough "extra detail" into topics we cover in lecture/section/lab. That said, let us know if you're looking for recommendations on a specific resource!

Tips for Module 2

  • There's a lot you can do with JavaScript - it will be overwhelming when you're first learning it, but focus on the problem you want to solve and then look through our slides/examples/readings to see what you can pull from to solve it.
  • If you don't know where to start, you're unsure about a resource you find online, or you're stuck on implementing a feature on CP2, don't hesitate to ask (via Piazza, attending OH, WPL, etc.). We have a staff that is very invested in helping students learn the cool things you can do with web programming!
  • Office Hours are an especially great resource to ask all kinds of questions, whether you're confused about a topic introduced in lecture, you want to learn how to implement something on a CP, or you want to learn material beyond the scope of the curriculum (also, you don't need to come with a question). Take advantage of them!

An Alternative Way to Handle Events

We introduced addEventListener as the way to give a "listener" to a DOM element, mapping an action (event) to a response (function).

Before addEventListener was introduced in JS, events were most often handled using "onevent" attributes. You will still see these occassionally, but addEventListener is the better choice.

Example: onclick

let myBtn = document.getElementById("my-btn");
myBtn.onclick = function() {
  console.log("You clicked a button!");
};

JS

let myBtn = document.getElementById("my-btn");
myBtn.addEventListener("click", function() {
  console.log("You clicked a button!");
});

JS

This is fine to use if you are attaching an event to an element and don't need to ever remove the event listener. It's an older convention, but not necessarily a "bad" one for simple event handling.

Another Example: window.onload

Recall that we need to set up our JS program with a listener for the window's load event in order to ensure access to DOM elements in our program when the document has finished loading.

window.addEventListener("load", initialize);

JS

You can achieve the same result using the onload event attribute for the window. You may see this in some examples, but addEventListener is preferred.

// initialize defined elsewhere
window.onload = initialize;

JS

window.onload = function() {
  // this is fine for short setup code, but it's common to factor 
  // your page setup into an "initialize" function as seen above
};

JS

Removing Event Listeners

We can also easily remove events using removeEventListener.

el.removeEventListener(event, responseFunction);

JS (syntax)

Note that this only works if responseFunction is a named function that has been added to the listener on el for the specified event (this is one motivation for preferring named functions over anonymous functions to handle events).

Removing Event Listeners: Example

function initialize() {
  let box = document.getElementById("box");
  box.addEventListener("mouseover", mouseOverResponse);
}
    
function mouseOverResponse() {
  console.log("You moved the mouse over a box!");
}
          
function turnOffBox() {
  let box = document.getElementById("box");
  box.removeEventListener("mouseover", mouseOverResponse);
}

JS