Handling Events with JavaScript

This is an action-packed chapter, where they introduce JavaScript, the DOM, events and event handlers all in one. We've spread that out over the last few class meetings, but now it's time to delve into what the chapter covered.

The main goal of the chapter is to add an event handler to the thumbnail otter pictures so that clicking on a thumbnail will cause that picture to be displayed in the larger version (called the detail image). This is a very cool and useful effect, often used in web pages with image galleries like this one.

If you don't have the book, here's a link to a copy of a scan of the chapter. To respect the author's copyright, the link is only valid on-campus or with a password. Ask Scott if you don't have that password.

FEWD Chapter 6

Recap

I won't try to recap everything in this dense chapter, but I'll try to remind you of the main points

  • we can add arbitrary information to a DOM element by adding attributes. To make sure that the attribute doesn't conflict with one that has meaning to the browser, we need to ensure that the first five characters of the attribute name is data-. For example, if I want to add information to an element about how classy it is, I could add a data-class=fancy attribute.
  • we can look up a DOM element using document.querySelector() where the argument is a string that contains a selector expression in the CSS language, such as #fred or .gryffindor or even [data-image-role="target"] which looks up an element that has that attribute/value pair.
  • the JS objects returned by querySelector have properties that we can modify, thereby updating the page. For example, obj.src="otter1.jpg" changes the src of an element (presumably an IMG), which would cause the browser to load and display a different picture.
  • there is a setAttribute() method that achieves the same effect
  • we should specify "use strict" as a string at the top of our JS functions to ask the browser to be a bit less permissive about possible errors. For example, if a variable hasn't been declared (maybe because you mispelled it) the browser will complain instead of just creating a new global.
  • we can attach a function as an event handler for an event using the .addEventListener() method. The function will be invoked by the browser whenever the event occurs
  • the function that we attach can either be named or anonymous, meaning a function expression or function literal, like function () { ... }
  • the argument function is passed in without parens after it, because parens would invoke the function and only pass in the return value. Instead, we want to pass in the function itself
  • the callback function is invoked with a JS object that contains a bunch of information about the event. This is called the event object
  • the event object has a method called preventDefault() which, if invoked, will cause the browser not to do the "normal" thing, whatever that normal thing is. In Ottergram, we're clicking on a hyperlink, and the normal thing is to visit the URL specified in the href. We want to not do that, so the event handler executes event.preventDefault where event is just the parameter that gets assigned the event object.
  • If we want to select more than one element (e.g. all the thumbnails), we can use document.querySelectorAll() Note that that returns a NodeList which is like an JavaScript array but doesn't support all the array methods. Best to iterate over it with a for loop. Alternatively, convert it to a JS array using [].slice.call.(*nodelist*)

Raw JS versus jQuery

Your book decided to defer the introduction of jQuery. This is a fine decision; they're already throwing a lot at you in this chapter. Because we're spreading the content out over several meetings, I decided to introduce jQuery. So, let's talk about the correspondence between raw JS and JQ.

Raw JSdocument.querySelector(sel_string)
jQuery$(sel_string)
useget a DOM element
Raw JSdocument.querySelectorAll(sel_string)
jQuery$(sel_string)
useget a list of DOM elements (jQuery always returns sets)
Raw JSelt.getAttribute(attrib_string)
jQueryjq_set.attr(attrib_string)
useget the value of an attribute
Raw JSelt.setAttribute(attrib_string,value_string)
jQueryjq_set.attr(attrib_string,value_string)
useset an attribute to a value
Raw JSelt.textContent = string
jQueryjq_set.text(string)
useset the text inside the element
Raw JSelt.addEventListener(event_type,callback_function)
jQueryjq_set.on(event_type, callback_function)
useattach an event handler to an element
Raw JSelt.addEventListener('click',callback_function)
jQueryjq_set.click(callback_function)
useattach a handler for click events to an element

You see that the jQuery methods are similar to raw JS, just as intuitive, more consistent (they are always methods, while raw JS is a mixture of methods and attributes), and more concise.

Note that we didn't learn jQuery's .on() method; instead, we learned a special case for click handlers, namely click(). I added on above for completeness. on has some advantages that we will discuss later in the course, but click is simple and easy.

Thumbnails

Note that in Ottergram, the same image file is used for both the thumbnail (small) and the detail (big) version. If there were many thumbnails, such that you expect most of them won't get clicked on, that would be a poor design, because your page would have downloaded many big images only to scale most of them down. Thus, your download would be increased for no benefit: a waste of time and bandwidth.

In Ottergram, there are only a few pictures, so the waste is negligible. In a different application, we might create special thumbnail versions. Note that their code doesn't assume that the URL of the detail image is the same as the URL of the thumbnail, so their code is ready for that improvement. That's good design.