Event listeners in javaScript

In javaScript event listeners are methods that fire some javaScript code when a given event happens. An event that fires or dispatches an handler can be something like a mouse button being clicked, or an element loosing focus. Event listeners can be used to create an application that is event driven in place of, or in combination with, some kind of of main update loop that mutates state. In many projects events are used at least to some extent as a way to capture user input from mouse clicks, changes to text area or input elements, or any other means in client side javaScript. In this post I will be covering the use of addEventListener as a way to attach events to elements in client side javaScript.

1 - Event listener basics

There is more than one way to attach event listeners in client side javaScript. For the most part it is a good idea to just stick to the addEventListener method as a way to attach events. The reason why is because more than one handler can be attach for a single event type. However there are also some alternative ways to do so as well that involve defining a method for certain properties of the window object..

1.1 - Attaching Event listeners using addEventListener

So lets start out with event listeners using the addEventListener method which is well supported with most modren web browsers these days. This works by gaining a reference to an element by whatever means, such as with document.getElementById, and then calling the addEventListener method of that element. The first argument that I give to addEventListener is the type of event I which to attach for, and the second argument is the method that I want to fire when this event occurs.

So I have some html for this example that looks like this.

1
2
3
4
5
6
7
8
9
<html>
<head>
<title>Event Listeners</title>
</head>
<body>
<input id="button" type="button" value="click me">
<script src="main.js"></script>
</body>
</html>

And the html links to an external main.js file that looks like this.

1
2
3
4
5
6
7
var button = document.getElementById('button');
button.addEventListener('click', function(e){
console.log('foo');
});

For the most part addEventListener should be used as a way to attach events to an element. This way if I want I can attach more than one handler for the same event and element. The only reason why I might want to bother with another way of doing so is maybe over backward compatibility concerns with older version of Internet explorer.

1.2 - element and window event properties

Another way of attaching event handlers is to set a function to one of many named properties of an element or the window object. One of the down sides of this is that only one event can be attached at a time. However doing so will work on a wide range of clients.

The process is more or less the same for elements in the sense that a reference to the element must be obtained first. Once a reference is gained an event listener function just needs to be set to a property name of the desired event.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html>
<head>
<title>Event Listeners</title>
</head>
<body>
<input id="button" type="button" value="click me">
<script>
var button = document.getElementById('button');
button.onclick = function(e){
console.log('foo');
}
</script>
</body>
</html>

There are also a range of events that can be attached to the window object also.

2 - The event Object of a call back when setting event listeners in javaScript

When setting an event listener there is the first argument of the callback that is given. This argument is the event object which contains all kinds of useful information about the event when the event triggers. This can contain things like a reference to the element that was clicked on an on click event, or the x and y position of where a canvas element was clicked on such an event and much more. Some parts of an event object depend on the type of event, for example you would not find a touches array of points on a touch screen for a keyboard event. However many other parts of such an event object are more or less consistent across different types. In this section I will be going over some examples of event objects when working with event listeners.

In this basic example of using an event object I am setting the href property of an anchor element using the target property of the event object. The target property is a reference to the element in which the event took place. So the target property can generally be used as a way to reference the element to which the event listener was attached inside the body of the event listener.

For this example I am just attaching a click event listener that will set the href property of a link when it is clicked.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<html>
<head>
<title>Event Listeners</title>
</head>
<body>
<a id="link" href="/" >some link</a>
<script>
var link = document.getElementById('link');
// using the target property of the event object
// to set the href property of a link
link.addEventListener('click', function(e){
e.target.href='https://www.google.com/'
});
</script>
</body>
</html>

2.2 - Stop propagation

When I have a situation in which I have a bunch of nested elements, and I have a handler attached for each of them. If an event happens in a child event, that event listener will of course fire. However each event listener all the way up to the parent event will also fire as well on top of that. If I want to prevent this from happening I will want to use the stop propagation event object method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<html>
<head>
<title>Event Listeners</title>
</head>
<body>
<div id="container" style="width:640px;height:240px;background:red;">
<div id="child1" style="width:240px;height:120px;background:green;">
<div id="child2" style="width:120px;height:60px;background:blue;">
</div>
</div>
</div>
<script>
[].forEach.call(document.getElementsByTagName('div'), function(div){
div.addEventListener('click', function(e){
e.stopPropagation();
console.log(e.target.id);
console.log(e.currentTarget.id);
});
});
</script>
</body>
</html>

4 - Not so basic example that uses canvas

Here I have a not so basic example of using event objects and event listeners that makes use of the canvas element. Here I am drawing some circles to a canvas with the arc canvas method. The position of the circles can be changed with the mouse click and mouse move event listeners.

When using mouse events the position of the mouse click,move event and so forth can be accessed via the event objects clientX, and clientY properties. However these values are window relative and not canvas element relative so I am using the getBoundingClientRect method to adjust those values to get a canvas relative x and y position.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<html>
<head>
<title>Event Listeners</title>
</head>
<body>
<div style="padding:50px;">
<canvas id="thecanvas" width="320" height="240"></canvas>
</div>
<script>
var app = {
canvas: document.getElementById('thecanvas'),
ctx: null,
circles: [],
// Using the event object to get the canvas
// relative position
getCanvasPos: function (e) {
var bx = app.canvas.getBoundingClientRect();
return {
x: e.clientX - bx.left,
y: e.clientY - bx.top
}
},
// set circle position based on event object
// and given circle index
setCircle: function(e, index){
var circle = app.circles[index],
pos = app.getCanvasPos(e);
circle.x = pos.x;
circle.y = pos.y;
app.draw();
},
clicked: function (e) {
app.setCircle(e,0);
},
move: function (e) {
app.setCircle(e,1);
},
init: function () {
this.ctx = this.canvas.getContext('2d');
this.circles.push({
x: 0,
y: 0,
radius: 25,
color: 'lime'
});
this.circles.push({
x: 0,
y: 0,
radius: 15,
color: 'red'
});
this.draw();
},
draw: function () {
var ctx = this.ctx;
ctx.fillStyle = 'grey';
ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.circles.forEach(function (circle) {
ctx.strokeStyle = circle.color;
ctx.lineWidth = 3;
ctx.beginPath()
ctx.arc(circle.x, circle.y, circle.radius, 0, Math.PI * 2);
ctx.stroke();
});
}
};
app.init();
// attach event listeners to the canvas
app.canvas.addEventListener('click', app.clicked);
app.canvas.addEventListener('mousemove', app.move);
</script>
</body>
</html>

When the example is up and running I can change the position of the circles by moving the mouse over the canvas, as well as clicking with the canvas with the click and mouse move event listeners. I could add many more listeners and make the project far more interesting, but you get the idea.

5 - Conclusion

There is way more to write about when it comes to event listeners in javaScript, there are a wide range of different types that have to do with all kinds of events. Events such as touch events, mouse events and there are even ways to write my own events and define what it is that triggers such custom events.