FAQ: DOM Events with JavaScript - Adding Event Handlers


#1

This community-built FAQ covers the “Adding Event Handlers” exercise from the lesson “DOM Events with JavaScript”.

Paths and Courses
This exercise can be found in the following Codecademy content:

Web Development

FAQs on the exercise Adding Event Handlers

There are currently no frequently asked questions associated with this exercise – that’s where you come in! You can contribute to this section by offering your own questions, answers, or clarifications on this exercise. Ask or answer a question by clicking reply (reply) below.

If you’ve had an “aha” moment about the concepts, formatting, syntax, or anything else with this exercise, consider sharing those insights! Teaching others and answering their questions is one of the best ways to learn and stay sharp.

Join the Discussion. Help a fellow learner on their journey.

Ask or answer a question about this exercise by clicking reply (reply) below!

Agree with a comment or answer? Like (like) to up-vote the contribution!

Need broader help or resources? Head here.

Looking for motivation to keep learning? Join our wider discussions.

Learn more about how to use this guide.

Found a bug? Report it!

Have a question about your account or billing? Reach out to our customer support team!

None of the above? Find out where to ask other questions here!


#3

Perhaps the author is referring to something like the following:

object.onclick = e => console.log(e.target)

The expression on the right is an anonymous function. We can write it that way, or we can give in a name and write it on the side, then use that name as a callback.

const log_target = e => console.log(e.target);

object.onclick = log_target;

Function expressions are called such since they are anonymous and either immediately executed, or assigned to a variable for later or repeated execution. Above we saw the use case for both.

Let’s examine one of JS’s iterators, Array.forEach(). This function takes a an anonymous function as an argument.

Array.forEach(function(x) {
    console.log(x);
});

We can write the function as a callback, and use it instead…

const log_x = x => console.log(x);

Array.forEach(log_x);

For each element in the array, the iterator will call the function on that element.


#4

Great response :grinning:. I realized what the author meant after doing more exercises - that’s why I removed my post (apparently while you were replying). Perhaps the lesson should be reworded to something like this: “It’s best practice to pre-define a callback function, instead of declaring an anonymous functions as part of the event handler property” since anonymous function does not necessarily mean unnamed.


#5

At this stage almost any manner of explanation is bound to be ambiguous for some, even confusing. There is no guarantee that revising the lesson text will have more or less ambiguity. No matter, we should expect to stumble a little until we get our bearings. Bear with it, and use the forums if you are unclear.


#6

Happy New Year, Roy!

I have a new question, but it is so closely related to this thread, I’m replying to this previously “closed-out” topic (I hope that’s consistent with the community guidelines - I’m still new). Here goes:

I noticed throughout this lesson that when we assign event handler functions to event properties, we omit the parenthesis when assigning a callback function. It wasn’t until I incorporated the learnings from this lesson into a personal project that I realized the parenthesis are omitted because we are not calling the function at the time we assign it to the event property… we are assigning the function to the property (which up till that point is empty - mind blown). I ran into problems when my callback function actually needed a parameter. My non-functional code looked something like this:

const doThis = function(index) {
  // something you don't need to see
  things[index].style.display = 'none';
  otherThings[index].style.display = 'block';
  //other things you don't need to see lol
}

for (let i=0;i<things.length;i++) {
  things[i].onclick = doThis(i);
}

Then the aha moment above hit me and I realized I needed to nest the contents of the callback function within a parameterless anonymous function:

for (let i=0;i<things.length;i++) {
  things[i].onclick = function() {
    // something you don't need to see
   things[i].style.display = 'none';
   otherThings[i].style.display = 'block';
   //other things you don't need to see lol
  }  
}

The above code functions exactly as I want it. Another approach occurred to me as I’m writing this post - I could just nest a call to doThis() within the anonymous function. My question was going to be how do I use a named callback function that takes a parameter, but I think I just answered it with the nested call. Do I grok it? Is there another approach that is more typical?

Thanks!


#7

Try this out for size…

things.forEach(x => x.onclick = doThis);

That can take the place of your for loop. forEach() is a JS iterator covered in the unit on iterators which should have been covered by now.


#8

I am familiar with forEach, but I don’t see how it could work here - not that your example wouldn’t work for some applications, but where do we pass in the parameter to doThis(index)? Read my post again. I will try to add more depth:

I have two arrays of equal length, each with values paired to the other by index (things[0] has a relationship with otherThings[0]). I want to associate a function for each click of the elements that belong to things that makes changes to those things elements and the corresponding elements of otherThings. Your example (unless I am mistaken and I am sorry if that is the case) would only work if doThis() takes in no parameters (e.g. modifies each index of things but only one index of otherThings). If I am wrong about your example, clearly my understanding of the syntax is incomplete. If so, please help me understand. Otherwise, as I said before, what I have works well (I did try nesting the function call per my previous post and that worked too!). I was only curious if there were other (perhaps more accepted) methods of doing what I did. Thanks again.


#9

The only parameter we need to supply the event handler is e or event which will be bound by the EventObject. What we call it is arbitrary since it is a internal variable.

We can identify the index of the event target (e.target), then apply it to another array.


#10

Okay cool. Got this to work. My code below:

 const doThis = function() {
   let index = things.findIndex(e => e === event.target);
   event.target.style.display = 'none';
   otherThings[index].style.display = 'block';
 }

things.forEach(elem => elem.onclick = doThis);

Compare this to my other solution:

const doThis = function(index) {
  things[index].style.display = 'none';
  otherThings[index].style.display = 'block';
}

for (let i=0;i<things.length;i++){
  things[i].onclick = function() {
     doThis(i);
  }
}

To select the best option, it looks to me like an optimization exercise. Although forEach() and findIndex() are built-in methods, they are still at their core loops. Even though the first solution does not require the developer to write a loop, it has nested loops - each iteration of the forEach() method must cycle through findIndex() iterations until its condition is satisfied. In contrast, the for loop solution is “single-axis.” Therefore I expect the for loop to be more efficient with machine time. Is this logic sound?