Browsers are busy pieces of software. Every tap, click, scroll, and keystroke is noticed by the browser. Each of these is an event that the browser may respond to. To make websites more dynamic and interactive, you can trigger your own code when one of these events occurs. In this section, you will add event listeners to each of your thumbnails.
An event listener is an object that, as the name suggests, “listens” for a particular event, such as a mouse click. When its assigned event occurs, the event listener triggers a function call in response to the event.
(Mouse events, like clicks and double-clicks, and keyboard events like keypresses are among the most common event types. For a complete listing of events, check the event reference in the MDN at developer.mozilla.org/en-US/docs/Web/Events.)
The addEventListener method is available on
every DOM element, including the document
.
As before, you will experiment with some code in the console first
and then use your tested code to write functions in main.js.
Switch to Chrome and enter the following code in the console. You will need to press Shift-Return to enter the line breaks. Press Return when you have finished typing all the code.
document.addEventListener('click', function () { console.log('you clicked!'); });
The code you entered added an event listener
for the document
object that is
listening for any clicks that occur on
the page. When a click happens, the event listener will print “you clicked!”
to the console using the built-in console.log
method (Figure 6.23).
Click on the header, the detail image, or the background. You should see that the text “you clicked!” appears printed in the console. (Do not click the thumbnails – those will take you away from Ottergram’s index.html page. When you are not on the index.html page, none of your markup, CSS, or JavaScript will be loaded and running in the browser.)
addEventListener accepts two arguments: a string with the name of the event and a function. This function will be run by addEventListener any time the event occurs for the element. The way this function is written may look a little strange at first. It is an anonymous function.
So far, you have worked with named functions, like setDetails and titleFromThumb. Named functions have names – no surprise there – and are created using function declarations.
You can also write literal function values,
the same way you can write literal number values like 42
and literal string values like "Barry the Otter"
.
Another name for literal function values is anonymous functions.
Anonymous functions are frequently used as arguments to other functions, like the one you passed as the second argument to document.addEventListener. This practice of passing a function to another function is quite common in JavaScript and is known as a callback pattern because the function you pass in as an argument will get “called back” at some point in the future.
It is perfectly fine to use a named function as a callback, but many front-end developers will use anonymous functions because they can provide more flexibility than named functions. You will see how this works shortly.
Now you will add an event listener for an individual thumbnail. Enter the following in the console. (Remember to use Shift-Return for the line breaks in the call to firstThumbnail.addEventListener.)
var firstThumbnail = document.querySelector(THUMBNAIL_LINK_SELECTOR); firstThumbnail.addEventListener('click', function () { console.log('you clicked!'); });
If you try clicking the first thumbnail (Barry the Otter, farthest to the left), your browser will take you to the large image of Barry. What
happened? Remember that each thumbnail is wrapped in an anchor tag with an
href
that points to an image, like
img/otter1.jpg.
This is the normal behavior of a browser when a user clicks a link: It has opened the file indicated by the href
attribute.
But you do not want to navigate away from Ottergram when a thumbnail is clicked, and you should not have to change your anchor tags to something else. Luckily, you can handle all of this from your callback function.
Recall from earlier in the chapter that functions carry out their tasks without you having to worry about the details. Usually you only need to know what information to pass as arguments and what information will be returned. When you pass a callback function as an argument, there is one more thing you need to know: what information will be passed to your callback.
When you call addEventListener, you are telling the
browser, “When the firstThumbnail
is clicked, call this
function” – and then the browser diligently waits for that element to be
clicked. If a click happens, the browser makes note of all the details
about the event (such as the exact position of the mouse, whether it was the
left or right mouse button, and whether it was a single or double click). The browser then passes
an object with this information to your function.
This object is an event object.
This relationship is diagrammed in Figure 6.24, using a made-up implementation of addEventListener.
In a moment, you will pass an anonymous function to addEventListener, just like before. But, this time, your anonymous function will expect to receive an argument. Make sure Ottergram is on the index.html page and enter the following in the console:
var firstThumbnail = document.querySelector(THUMBNAIL_LINK_SELECTOR); firstThumbnail.addEventListener('click', function (event) { event.preventDefault(); console.log('you clicked!'); console.log(event); });
The browser will call your anonymous
function each time firstThumbnail is clicked,
and it will pass your anonymous function the event object. Using this object (which you
have labeled event),
you call its preventDefault method.
This method will stop the link from taking the browser to a different
page. Finally, you call console.log on the
event
object so that you can inspect it in the DevTools.
Now click on the first thumbnail. Your browser
remains on the Ottergram page and the event is
logged to the console: MouseEvent {isTrusted: true}
.
If you click the disclosure arrow
next to MouseEvent
, you should see quite a bit
of information about the event (Figure 6.25),
including the mouse coordinates on the page, which mouse button was
clicked, and whether any special modifier keys were pressed during the click.
For now, do not focus on the different properties of the event object. Just know that it carries lots of information about the browser event that was triggered.
By the way, it is not required that the callback function’s parameter be named event
– it will
be mapped to the value that is passed in no matter what you name it.
You can use whatever parameter names you like, but it is good practice to
use descriptive names, as you have done here, to make your code easier to
read and maintain.
You now have a function that accepts a thumbnail and adds an event listener.
Add a function declaration to main.js
for addThumbClickHandler. It should
define a parameter named thumb
.
You can copy your experimental addEventListener code
from the console and paste it into the body of
addThumbClickHandler. Modify it
so that you are calling thumb.addEventListener.
For now, you will only need the call to
event.preventDefault
in the event callback.
... function setDetailsFromThumb(thumbnail) { ... } function addThumbClickHandler(thumb) 'use strict'; thumb.addEventListener('click', function (event) { event.preventDefault(); }); }
Inside the event callback, you have access to the
thumb
parameter declared as part of
addThumbClickHandler.
Pass it to a call to setDetailsFromThumb.
... function addThumbClickHandler(thumb) { 'use strict'; thumb.addEventListener('click', function (event) { event.preventDefault(); setDetailsFromThumb(thumb); }); }
JavaScript, like many other programming languages, has rules about defining and accessing variables and functions. The anonymous function you passed to addEventListener is able to access the setDetailsFromThumb function because setDetailsFromThumb was declared in the global scope. This means that it can be accessed from any other function or from the console. The same is true for variables like DETAIL_IMAGE_SELECTOR, which is also declared in the global scope.
However, the variables detailImage and detailTitle, which you declared inside setDetails, are only available within the body of setDetails. You cannot access them from the console or from other functions. These variables are declared in the function scope (or local scope) of setDetails. A function’s parameters work very much like variables declared inside a function. They too are part of that function’s scope.
Normally, functions cannot access variables or parameters that are part of another function’s scope. addThumbClickHandler is interesting because it defines the parameter thumb, which is accessed by another function – the callback function you passed to addEventListener. This is possible because the callback function is part of addThumbClickHandler’s scope.
You can read more about how all of this works in a For the More Curious section at the end of this chapter.
18.225.255.187