Review of events

So far you have added event triggers into the HTML opening tag.  That is easy because you can easily see what events are associated with what elements.  There are two reasons why it is not perfect:

  1. it clutters up your HTML with stuff that is not HTML
  2. it only allows you to have one thing happening per event

A reminder of some terms before you get started:

So you can probably guess that this:

<body onmouseup="runSomeCode();">

sets up an event listener which monitors for any mouse clicks within the page and then runs a functions when it hears one.  There is another way of achieving exactly the same thing.

The old way

Create a new page called addevent.html.  At first do it the old fashioned way by adding an event trigger in the body tag:

<body onmouseup="runSomeCode();">

In the script element paste these functions:

function runSomeCode(){
    alert('hi');
}
function runSomeOtherCode(){
    alert('bye');
}

You will need some text on the page so it is visible to click on so if you do not have a heading put some text into the h1 element.  Load the page and click.

You also learned how to pass the event object to the function so that it can use the event properties.  Add that to the existing trigger:

<body onmouseup="runSomeCode(event);">

and function:

function runSomeCode(e){
    alert('hi');
}

The page should still work as before.  That was just a reminder so you understand what is coming up.

addEventListener

Delete the onmouseup leaving just a simple body tag.  In your script element add a new line of code just before the function:

document.addEventListener('mouseup', runSomeCode(event));

Try it and it should work as it did before except that the function runs once without you clicking.  This is because of a syntax/execution quirk but just change that new line to:

document.addEventListener('mouseup', function(){runSomeCode(event)});

Now the function is no longer called immediately when the browser "reads" the function name in setting up the event listener.  If you look at what was added it is just a null function wrapped around the name of the one you want to run later to protect it.

Other elements

You can add events to other elements using getElementById.  Add an id with the value mainHeading to the h1

<h1 id="mainHeading">Click me</h1>

Now add this line before the existing first line of JavaScript:

document.getElementById('mainHeading').addEventListener('mouseup', function(event){runSomeOtherCode(event)});	

When you try it nothing works any more.  Look at your error console and there will be a clue.  You cannot add an event listener to the heading because, at the time the code is run, it does not exist yet.

Start the event listeners after load

To allow the page to load before you start adding event listeners you need to do the adding after load.  To delay any code from running you put it in a function and call that function at the right time:

  1. move the two addEventListener lines into a new function called createListeners()
  2. add this line as the new first line of JavaScript:
document.addEventListener('DOMContentLoaded', function(event){createListeners(event)});

This sets up a listener which is triggered once the page has finished loading.  Unlike onload (which would be load when used here) onDOMContentLoaded (without the on here) is triggered when just the HTML DOM has finished loading.  Otherwise the event listeners would only be added once the compete page and all the resources such as images, videos etc. had finished loading and by then the user might be clicking.  So the process is now:

  1. once the HTML is loaded the createListeners() function is run
  2. that creates two more listeners (one for the whole page and one for the heading)
  3. when the user clicks something will now happen (but maybe not the right thing as explained below)

Bubbling and capturing

At the moment if you click on a blank part of the page you get the correct message.  If you click on the heading you get both.  This is because you have added an event listener for the same event to both the body/document and to the heading.  So when you click on the heading both listeners react, first the heading one and then the body one.  This is known as bubbling because the event is passed up through the DOM like a bubble.  This is the default behaviour.  It is also possible to have the event listeners react in the opposite order (parent first) by adding an option to the event listener to enable capturing (sometimes known as trickling because that is what happens).  Change both of the addEventListener lines by adding true:

document.getElementById('mainHeading').addEventListener('mouseup', function(event){runSomeOtherCode(event)}, true);			
document.addEventListener('mouseup', function(){runSomeCode(event)}, true);

Try the page again and you should get the messages in the opposite order.

Stopping propagation

This is why the event object has been passed to all the functions.  If we want just one message to show when the user clicks on the heading we need to stop the event from bubbling or trickling.  In both functions (runSomeCode and runSomeOtherCode) add this new line after the alert line:

e.stopPropagation();

Try clicking on the heading and you should now only get one message.  The message you get depends on whether capture is true or false.  If true the parent element grabs the event and executes the function triggered by the first event listener you created.  If false the object you clicked on gets first go and then stops propagation.  Try changing true to false and back to check.

Should I use it?

This method is obviously more complicated than using triggers inside HTML tags.  Therefore if you use it you are more likely to make mistakes.  Therefore if you will only use occasional JavaScript to do a couple of things on a page you might as well stick with the old way.  That is why this site starts with it.

However, if there is any chance you will start to create complex interactive pages where users can do many things and achieve many end results you should probably start practising with addEventListener.  Any Web application like Google Drive will not be using the old methods because they are too restrictive.  Using the modern method allows for games, animations and complex applications.