Intro to DOM Events
Events - Responding to user inputs and actions
Types of events:(some of the many)
- clicks, drags, drops, hovers,scrolls, form submissions, key press, focus/blur
- mousewheel, double click, copying, pasting, audio start, screen resize, printing etc.
Note: All events follow a similar pattern
Pattern:
The thing Event type Code to run button click change the color input hits return get the search results image mouseover display img caption for more info visit MDN Event reference
2 ways not to add events
Lets explore 2 different syntaxes which we should not use.
- all events start with
on
word. onEventName = doSomething
- First type actually involves inline html scripting, which is not recommended. It just clutters the markup.
1<button onmouseover="alert('You hovered over me!')">click me!</button>
2<form>
3 <input
4 type="range"
5 min="50"
6 max="100"
7 onclick="console.log('clicked the input')"
8 />
9</form>
- We first select an element in Javascript and then do inline html scripting
1<button id="clicker">CLicker!</button>;
2
3const clicker = document.querySelector("#clicker");
4
5clicker.onclick = function () {
6 console.log("You clicked me");
7};
8clicker.ondblclick = function () {
9 console.log("Double click");
10};
11
12clicker.onclick = function () {
13 alert("hello");
14};
15//now we lost the previous data.
16//Onclick is considered just like any other property
- if you want to have multiple events to a single element use
addEventListener
addEventListener
Specify the event type and a callback to run
1const button = document.querySelector("h1");
2button.addEventListener("click", () => {
3 alert("You clicked");
4});
5
6button.addEventListener("click", () => {
7 console.log("Output in console");
8}); // we get both things as output for one event. one in console and other as alert
9button.addEventListener("mouseover", function () {
10 button.innerText = "Dont hover on me";
11}); // we are permanently changing the innerText, the text doesnt go back to its prev state
12// to get the text to its prev state. there is another event called `mouseout` use that.
13button.addEventListener("mouseout", function () {
14 button.innerText = "CLick me!";
15}); // now text changes back to prev state
addEventListener() is great, because it is just one method and it will attach to any type of event listener you want(click, double click, mouseover etc…)
- Note: if you see
button.onclick
property, it is not attached to anything. It returns null as output
important: Dont use arrow functions as call backs, because sometimes we want to access
this
inside the function and arrow functions doesnt do well withthis
Events on Multiple Elements
This is the important topic of event handling. We know how to add multiple events to a single element. how about multiple elements having a single event? How do we take every button on page and add a click event?
- select a group of items u want to add events to
- loop over them and add eventlistener to each
Note:
this
refers to individual object onto which we are listening over when adding multiple events
Exercise:
1<body>
2 <h1>Pick a color</h1>
3 <section class="boxes" id="container"></section>
4 <script src="app.js"></script>
5</body>;
6
7const colors = [
8 "red",
9 "yellow",
10 "orange",
11 "green",
12 "blue",
13 "purple",
14 "indigo",
15 "violet",
16];
17const boxes = document.querySelector("#container");
18const heading = document.querySelector("h1");
19const pickAColor = function () {
20 console.log(this);
21 heading.style.color = this.style.backgroundColor;
22};
23
24for (let color of colors) {
25 const box = document.createElement("div");
26 box.style.backgroundColor = color;
27 box.classList.add("box");
28 boxes.appendChild(box);
29 box.addEventListener("click", pickAColor);
30}
Important : So when the function pickAColor is called, ie., when we click on a box, we are never executing pickAColor ourselves, its being called for us. An Event object is passed to it. Event object is automatically called every time we are not capturing it
Event Object
Contains information about a particular event
1const pickAColor = function (evt) {
2 console.log(evt); //MouseEvent Object is returned
3};
1document.body.addEventListener("keypress", function (e) {
2 console.log(e);
3}); //RT: KeyboardEvent
- KeyboardEvent - Conatins info about the key we pressed and othe useful info about keys
Key Events
There are atleast 3 types of keyevents.
keyup
keydown
keypress
keydown
A Key has been pressed.
When u hold or press any key it is considered as keydown event.
Note: keydown runs for any potential keys whether they actually change the input or not
All key presses are considered as keydown events.
- eg: alt/option, cmd, ctrl, caps, all alphabets, space, shift, tab etc.
1<input type="text" id="username" placeholder="username" type="text" />
1const username = document.querySelector("#username");
2//we would want event object, because it contain info about which key is pressed
3username.addEventListener("keydown", function (e) {
4 console.log("KEY DOWN");
5});
keyup
A key has been released.
For all keys, first a keydown event is fired followed by a keyup.
- Note: keyup only occurs when u release a key
1const username = document.querySelector("#username");
2
3username.addEventListener("keydown", function (e) {
4 console.log("KEY DOWN");
5});
6username.addEventListener("keyup", function (e) {
7 console.log("KEY UP");
8});
keypress
A key that normally produces a character value has been pressed. If the key is not a modifier key, the keypress event is sent
Caution: This event is obsolete and differs from browser to browser, better not to use it much
When you type a key K in the input. The order of key sequenes would be Keydown, keypress, keyup
When you press something like shift we only get keydown and keyup
Capital letter -> Shift + Letter -> KeyDown(2) , keypress, keyup(2) -> keydown and keyup for both shift and letter
Note: keypress only works when we have changing input. like alphabets, doesnt work with arrows, caps, shift, tab, cmd etc. But when you hit return, it is considered as a keypress
For more on events WEBApi - MDN
Example
Lets make a todo list
1<h1>Shopping list</h1>
2<input type="text" name="" id="addItem" placeholder="add items in your list" />
3<ul id="items"></ul>
1const input = document.querySelector("#addItem");
2const ulItems = document.querySelector("#items");
3
4input.addEventListener("keypress", function (e) {
5 // doesnt allow spaces in the beginning
6 if (e.which === 32 && !this.value.length) {
7 e.preventDefault();
8 }
9 if (e.key === "Enter") {
10 if (!this.value) return;
11 const item = document.createElement("li");
12 item.innerText = this.value;
13 console.log(item);
14 this.value = "";
15 ulItems.appendChild(item);
16 }
17});
FormEvents & preventDefault
When we press submit, we get navigated to other page or the page gets refreshed if we dont specify any url in action.Lets say we want to stop the form from getting refreshed when we submit. Capture the submit event and stop it from its default behaviour.
Lets take this html snippet
1<form id="signup">
2 <input type="text" placeholder="credit card" id="cc" />
3 <label>
4 I agree to T&C
5 <input type="checkbox" id="terms" />
6 </label>
7 <select id="veggies">
8 <option value="brinjal">Brinjal</option>
9 <option value="tomato">Tomato</option>
10 <option value="onion">Onion</option>
11 </select>
12 <button type="submit">Submit</button>
13</form>
preventDefault
Default behaviour is prevented
1const form = document.querySelector("#signup");
2form.addEventListener("submit", function (e) {
3 e.preventDefault(); //when this is executed default behaviour is prevented
4});
Now this leaves us free to now extract data from the submit event. If we wanted all data at once and send it to an api using AJAX or using a client side request, we can do that. We have flexibility to do something with the data and we can still capture the submit event. What’s nice about doing this way as opposed to capturing each input as it changes every single time is we dont need to attach a bunch of event listeners for every input, by adding a submit event listener there’s just one event we are waiting for, we tell it not to behave, normally it behaves and then we can extract our data in that function.
1const creditCardInput = document.querySelector("#cc");
2const termszcheckBox = document.querySelector("#terms");
3const veggiesSelect = document.querySelector("#veggies");
4const form = document.querySelector("#signup");
5form.addEventListener("submit", function (e) {
6 console.log("cc", creditCardInput.value); //cc 12343434535
7 console.log("terms", termszcheckBox.checked); // terms true
8 // we get the value from value attribute, eg: we get brinjal as output instead of Brinjal
9 console.log("veggiesSelect", veggiesSelect.value); //veggiesSelect tomato
10 e.preventDefault();
11});
We are accessing data from the form. After accessing these values , we can generally send form data to DB or append something to page using form data. We can put preventDefault() at the top of the function, it still works the same
input
and change
Events
input
This event is triggered whenever an input changes .We can actually listen to all 3 above inputs(textbox, checkbox and select) at once using a single event type.
Our goal is to create a datastructure which automatically updates whenever a user enters value in input, instead of waitiing for user to submit(like from the above section)
1creditCardInput.addEventListener("input", (e) => {
2 console.log("CC Changed", e); // the event is triggered whenever we type something in the input box
3});
Storing value to an object as soon as user changes the input. These events trigger before user clicks submit.
1const formData = {};
2creditCardInput.addEventListener("input", (e) => {
3 console.log("CC Changed", e);
4 //formData['cc'] = creditCardInput.value; -> hard coding. instead use event object properties to get value
5 formData["cc"] = e.target.value;
6});
7veggiesSelect.addEventListener("input", (e) => {
8 console.log("veggie change", e);
9 formData["veggie"] = e.target.value;
10});
11termszcheckBox.addEventListener("input", (e) => {
12 console.log("terms changed", e);
13 formData["terms"] = e.target.checked;
14});
Refactor the above code.
add a name
attribute to each html input
1<input type="text" placeholder="credit card" id="cc" name="creditcard" />
2<label>
3 I agree to T&C
4 <input type="checkbox" id="terms" name="agreeToterms" />
5</label>
6<select id="veggies" name="selectedVeggie">
7 <option value="brinjal">Brinjal</option>
8 <option value="tomato">Tomato</option>
9 <option value="onion">Onion</option>
10</select>
1for (let input of [creditCardInput, termszcheckBox, veggiesSelect]) {
2 input.addEventListener("input", (e) => {
3 if (e.target.type === "checkbox")
4 formData[e.target.name] = e.target.checked;
5 else formData[e.target.name] = e.target.value;
6 });
7}
8// more sophisticated code
9for (let input of [creditCardInput, termszcheckBox, veggiesSelect]) {
10 input.addEventListener("input", ({ target }) => {
11 // destructure event object since we only use target
12 // destructure more coz we use only these 4 properties in target
13 const [name, type, value, checked] = target;
14 formData[name] = type === "checkbox" ? checked : value;
15 });
16}
- We can add multiple events under single event listener as long as we have
name
attribute.
change
If we change the above event type to change
it will still behave the same except for the textbox. Textbox input change wont trigger until we lose focus over it or press return key after entering complete data or focus it, unlike input where it triggers event for every single key typed(every single letter changed in text box).
1for (let input of [creditCardInput, termszcheckBox, veggiesSelect]) {
2 input.addEventListener("change", ({ target }) => {
3 // destructure event object since we only use target
4 // destructure more coz we use only these 4 properties in target
5 const [name, type, value, checked] = target;
6 formData[name] = type === "checkbox" ? checked : value;
7 });
8}
This type of pattern (using name attribute) is pretty common especially if we get to something like react and some of the other frameworks or libraries out there. We use name of an input as a key to store the value from that input under, to create a nice object that contains all of our form data at once.