Ways to assign events

Before getting events live on a webpage we have to assign them to the elements we desire them on.

And to assign events to a given element we first have to select it using the ways discussed in the HTML DOM - Accessing Elements) chapter. After selecting it we then need to simply assign it the desired event using one of the following methods.

  1. HTML event's attribute
  2. Event's property
  3. Listener method.

We'll discuss each of these methods in detail below but first let's consider the simple HTML example below on which we will base our further discussion.

<button>Click Me!</button>

Now what we want to do, is to show an alert whenever someone clicks on this button. We will be needing the click event for this. The click event executes when you click on an element.

To accomplish the task of assigning a click event to the element button we have quite a few options. Let's see each one:

The HTML attribute way

The first way is to use the respective event's HTML attribute.

The attribute for assigning a click event is onclick. There are different attributes for different events. Just to name a few we have onmouseover for when the pointer is brought over an element, onfocus when an HTML input element is in focus, onkeypress when a key is pressed and such many more.

The value for the event's attribute is a complete code of JavaScript to be executed only when the corresponding event takes place. Nothing inside an event's attribute is executed unless and until the event gets fired. The value of an event's attribute is often refered to as inline JavaScript - you can literally have a whole script inside the attribute!

Let's see this in action:

<button onclick="alert('Button clicked')">Click Me!</button>

So here we have an onclick attribute for the button element and its value, which in this case is alert('Button clicked'), is the JavaScript code to be executed when the event gets fired/called. And now if someone clicks the button he/she will get an alert! Simple as a cake!

Now despite the fact that assigning events this way is very simple, it is nowadays not recommended. Why? Simply to keep JavaScript code seperate from HTML code. If a developer needs to make some adjustments to JavaScript code he can simply go to a seperate .js file, make the adjustments and everything works fine. Compared to this if there was JavaScript code in an HTML file, the developer will have to search for the specific HTML document, scroll to the respective section and then make the changes. More work and clearly not as good as compared to the latter approach!
Understanding this thing is very important as we will move on to the next way of assigning events.

The event's property way

Second in the list we have an event's HTML DOM property to assign it to a given element.

Let's see how to add a click event to the button element using this choice. Below we only have the JavaScript code for the task. The HTML code is the same as in the first example:

// assign an event to button
button.onclick = function() {
    alert("Button clicked");

Here we first select the button using getElementsByTagName() method and then assign it a click event using the onclick property. The property contains a function definition that gets executed when ever the event gets fired.

Now you may be thinking why we created an anonymous function and put an alert call in it. Why we didn't just use the following code by directly writing alert.

button.onclick = alert("Button clicked");

Go on and write this code inside your HTML page and see what you get. Well you will get an alert as soon as the page loads. But why does this happen? The same didn't happen for the onclick attribute. Take a minute and try to think for an answer. It's very simple actually.

A JavaScript interpreter is different from an HTML interpreter. In the wrong code above as soon as the JavaScript interpreter encounters the alert function's call in line 4, it executes it and we get an alert readily. In fact, regardless of the place where function calls are made in a script, for example function parameters, property values, etc, the functions will be executed and the returned values will be the script dealers afterwards.

Compared to this, in the example with the onclick attribute we had the same thing - alert("Button clicked") however it worked perfectly fine! This is because as soon as the HTML interpreter reads the onclick attribute it assigns the given value to it, which is a script to be executed only when the click event occurs.

If you didn't understand some parts in the answer above or nothing at all don't worry. Everything will start working as you see the examples below.

So this means that we can't just call the alert function directly owing to its nature (as we will see later). We clearly need something else and that is a function definition! This means that we can in our first solution just write alert without the ( ) parentheses.

The second solution is the first example in the explanation of the onclick property using anonymous functions as you will be explained below.
button.onclick = alert;

However to surprise you even this doesn't work! We get an Illegal Invocation error thrown. Even if it did work, notice one thing that in this way we can't send in parameters to alert and any other function. But the good news is that this is not the case with all other functions. Depending on the function we want to get executed as an event happens we can, just like here, only write its name and get things working.

Consider the example below in which on every button click we get a function executed by just providing its name in the onclick property.

// a function adding two numbers
function sum() {
    console.log(10 + 10);

button.onclick = sum; // assign the definition of demo. Don\'t call the function here like demo()

So each time the button is clicked we get a function namely sum executed/invocated. And in this way we can use any other custom function to handle a given event only if it doesn't require any arguments. But what if the function needs some arguments? Then we need to employ anonymous functions or closures.

For anonymous functions consider this example. Read the comments in the code for explanation as you move on:

// a function adding two number arguments
function sum(x, y) {
    console.log(x + y);

var x = 10, y = 10; // demo variables to test argument functionality

button.onclick = function() { // this is the anonymous function
    sum(x, y);

We are inside a function's definition and therefore sum won't be executed until the anonymous function, as the value of the onclick property, gets called. Remember that only when a function gets called does anything inside it gets executed.

For the closure part consider this example, again for adding two numbers but now by slightly altering sum:

// a closure function
function sum(x, y) {
    return function() { console.log(x + y); } // a function adding two numbers

var x = 10, y = 10; // demo variables to test argument functionality

button.onclick = sum(x, y); // call sum and return another function to add the given arguments in sum

Closures mean that we can have function calls also in event properties like onclick since the function gets called and another function gets returned (remembering the variables of the previous function). We covered closures in the function closures chapter so we won't discuss the details over here again.

When working with events in JavaScript take special care of what are you writing and where. You should be able to make the differentiation between an event's property and its similar attribute. You should also know when to assign anonymous functions, named functions, function calls etc.

The listener way

The third and the last way to assign events in JavaScript is using the addEventListener() method. Let's first see its syntax:

addEventListener(eventName, eventListener, capture)
  1. string eventName is the name of the event to be assigned, for example click, as a string.
  2. function eventListener is the listener for the event i.e the function to be executed when the event takes place.
  3. boolean capture indicates whether the event should be handled in the CAPTURING phase (for true) or the BUBBLING phase (for false) which is the default.

Now let's even put this syntax into real action:

button.addEventListener("click", function(){
    alert("Button clicked");

First we select the button element and then add a listener to it for the click event, as indicated by the first argument. The listener in this case is an anonymous function that calls alert("Button clicked"). The listener could've also been a named function like in the example below.

// a function with a name
function makeAlert() {
    alert("Button clicked");

button.addEventListener("click", makeAlert);

Here everything is exactly the same except for the handler function which is now a named function instead of an anonymous one as in the previous example.

Notice one thing in the second example that we didn't write makeAlert() in the second argument of the method. Writing this would mean that we are calling the function makeAlert not assigning its defintion!
With named functions you get an advantage of being able to remove a specific handler as you'll see later.
We didn't provide the third argument for the addEventListener method in both the examples above since it is optional. We only need to provide it if we want to change from the default behaviour of bubbling. More on this later.