Event

An event is a signal that something has happened. All DOM nodes generate such signals (but events are not limited to DOM).

Event Handlers

To react on events we can assign a handler – a function that runs in case of an event. Handlers is a way to run JavaScript code in case of user actions. There are several ways to assign a handler. Let’s see them, starting from the simplest one.

HTML Attribute

A handler can be set in HTML with an attribute named on<event>.

For instance, to assign a click handler for an input, we can use onclick, like here:

<input value="Click me" onclick="alert('Click!')" type="button">

In the above example, if you click the button above, it will give an alert message. However, this way is not good to write multiple statement and execute them. For this case, we need to create function and pass the function on the attibute, like this -

<input value="Click me" onclick="getSum()" type="button">

function getSum(){
	var firstName = "Santanu";
	var lastName = "Bera";
	alert("Full Name = " + firstName + " " + lastName);	
}

HTML Attribute are case-insensitive

As we know, HTML attribute names are not case-sensitive, so ONCLICK works as well as onClick and onCLICK… But usually attributes are lowercased: onclick

DOM Property

We can assign a handler using a DOM property on<event>. For example -

<input id="elem" type="button" value="Click me">
<script>
  elem.onclick = function() {
    alert('Thank you');
  };
</script>

If the handler is assigned using an HTML-attribute then the browser reads it, creates a new function from the attribute content and writes it to the DOM property. So this way is actually the same as the previous one.

The handler is always in the DOM property: the HTML-attribute is just one of the ways to initialize it.

As there’s only one onclick property, we can’t assign more than one event handler.

<input type="button" id="elem" onclick="alert('Before')" value="Click me">
<script>
  elem.onclick = function() { // overwrites the existing handler
    alert('After'); // only this will be shown
  };
</script>

We can directly assign function name

function sayThanks() {
  alert('Thanks!');
}

elem.onclick = sayThanks;

Use Function, not String

While assigning function name to the event property, you should always assign function, not string. Consider the following -

element.onclick = "functionName()";

The above will work too for compibility reason. But it is not recomended. Always use function like the following -

element.onclick = functionName;

DOM property are case-sensitive

Assign a handler to elem.onclick, not elem.ONCLICK, because DOM properties are case-sensitive. So always use lowercase for the DOM property for Events.

Removing Event handler

You can assign null to the on<event> to remove an event handler.

element.onclick=null;

Accessing the Element : this

The value of this inside a handler is the element. The one which has the handler on it.

In the code below button shows its contents using this.innerHTML:

<button onclick="alert(this.innerHTML)">Click me</button>

Don's use setAttribute

Never ever use setAttribute to assign event handler. The following won't work at all -

// a click on <body> will generate errors,
// because attributes are always strings, function becomes a string
document.body.setAttribute('onclick', function() { alert(1) });

addEventListener

The fundamental problem of the aforementioned ways to assign handlers – we can’t assign multiple handlers to one event. For instance, one part of our code wants to highlight a button on click, and another one wants to show a message. We’d like to assign two event handlers for that. But a new DOM property will overwrite the existing one:

input.onclick = function() { alert(1); }
// ...
input.onclick = function() { alert(2); } // replaces the previous handler

Web-standard developers understood that long ago and suggested an alternative way of managing handlers using special methods addEventListener and removeEventListener. They are free of such a problem.

The syntax to add a handler:

element.addEventListener(event, handler[, phase]);
<button id="element3">Click Me</button>
<script type="text/javascript">
element3.addEventListener('click', function(){
	var value = 30;
	alert(value);
});
</script>

Assigning Multiple event handlers -

<button id="element4">Click Me</button>
<script type="text/javascript">
element4.addEventListener('click', function(){
	var value = 30;
	alert(value);
});
element4.addEventListener('click', function(){
	alert(this.innerHTML);
});
</script>

Some events only work with addEventListener

There exist events that can’t be assigned via a DOM-property. Must use addEventListener. For instance, the event transitionend (CSS animation finished) is like that. Try the code below. In most browsers only the second handler works, not the first one.

<style>
  input {
    transition: width 1s;
    width: 100px;
  }

  .wide {
    width: 300px;
  }
</style>

<input type="button" id="elem" onclick="this.classList.toggle('wide')" value="Click me">

<script>
  elem.ontransitionend = function() {
    alert("DOM property"); // doesn't work
  };

  elem.addEventListener("transitionend", function() {
    alert("addEventListener"); // shows up when the animation finishes
  });
</script>

removeEventListener

To remove the handler, use removeEventListener:

// exactly the same arguments as addEventListener
element.removeEventListener(event, handler[, phase]);

To remove a handler we should pass exactly the same function as was assigned.

That doesn’t work -

elem.addEventListener( "click" , () => alert('Thanks!'));
// ....
elem.removeEventListener( "click", () => alert('Thanks!'));

The handler won’t be removed, because removeEventListener gets another function – with the same code, but that doesn’t matter.

Here’s the right way:

function handler() {
  alert( 'Thanks!' );
}

input.addEventListener("click", handler);
// ....
input.removeEventListener("click", handler);

Please note – if we don’t store the function in a variable, then we can’t remove it. There’s no way to “read back” handlers assigned by addEventListener.

Event Object

To properly handle an event we’d want to know more about what’s happened. Not just a “click” or a “keypress”, but what were the pointer coordinates? Which key was pressed? And so on.

When an event happens, the browser creates an event object, puts details into it and passes it as an argument to the handler. Here’s an example of getting mouse coordinates from the event object:

<input type="button" value="Click me" id="elem">

<script>
  elem.onclick = function(event) {
    // show event type, element and coordinates of the click
    alert(event.type + " at " + event.currentTarget);
    alert("Coordinates: " + event.clientX + ":" + event.clientY);
  };
</script>

Some properties of event object:

There are more properties. Some of them specific to the type of event. You can console log the whole objet to get an idea what properties available to you for a particular event type.

The event object is also accessible from HTML

If we assign a handler in HTML, we can also use the event object, like this:

<input type="button" onclick="alert(event.type)" value="Event type">

For HTML attribute you need to pass the event -

<button onclick="sayThankYou(event)">Thank you</button>
<script type="text/javascript">
function sayThankYou(event){
	alert(event.target.innerHTML);
}
</script>

However, the following won't work, it will result an error - "Cannot read property target of undefined" as we are not passing the event -

<button onclick="sayThankYou()">Thank you</button>
<script type="text/javascript">
function sayThankYou(event){
	alert(event.target.innerHTML);
}
</script>

Handlers as an Object : handleEvent

Instead of using function as event handler, we can use object as an event handler. In this case, the object must have a function called handleEvent. So whenever the event occurs, the handleEvent method runs of the object. Here is an example -

<button id="elem">Click me</button>

<script>
  elem.addEventListener('click', {
    handleEvent(event) {
      alert(event.type + " at " + event.currentTarget);
    }
  });
</script>

In other words, when addEventListener receives an object as the handler, it calls object.handleEvent(event) in case of an event.

We could also use a class for that:

<button id="elem">Click me</button>

<script>
  class Menu {
    handleEvent(event) {
      switch(event.type) {
        case 'mousedown':
          elem.innerHTML = "Mouse button pressed";
          break;
        case 'mouseup':
          elem.innerHTML += "...and released.";
          break;
      }
    }
  }

  let menu = new Menu();
  elem.addEventListener('mousedown', menu);
  elem.addEventListener('mouseup', menu);
</script>

In the above example, the same method handleEvent defines handler for mousedowna and mouseup, you can define other handlers too. But the thing is that, the same method would handle all type of event.

The method handleEvent does not have to do all the job by itself. It can call other event-specific methods instead, like this:

<button id="elem">Click me</button>

<script>
  class Menu {
    handleEvent(event) {
      // mousedown -> onMousedown
      let method = 'on' + event.type[0].toUpperCase() + event.type.slice(1);
      this[method](event);
    }

    onMousedown() {
      elem.innerHTML = "Mouse button pressed";
    }

    onMouseup() {
      elem.innerHTML += "...and released.";
    }
  }

  let menu = new Menu();
  elem.addEventListener('mousedown', menu);
  elem.addEventListener('mouseup', menu);
</script>

Now event handlers are clearly separated, that may be easier to support.