0

I am new to JavaScript, I've done most of my coding in Python, and haven't found a clear answer to this question.

If I have an object containing element ids and function parameters, and I want to add event handlers (pointing to the same function) to the ids inside the object - how do I do it?

I've been looping over them using a for loop and adding "click" listeners on them, but as I loop through, the function is executing instead of just putting the event listener on.

I see this as my next step in writing more efficient JavaScript and would love some pointers.

var delay2 = 1000; //smooth scroll time
scroll_list = {
 "review":"book_apt",
 "review2":"book_apt",
 "home_nav":"home",
 "what_wedo_nav":"what_we_do",
 "save_early_nav":"save_early",
 "reviews_nav":"reviews",
 "our_team_nav":"our_team"
}
// loops through scroll list. 
for (key in scroll_list){
 let id = document.getElementById(key); //gets id from object
 id.addEventListener("click", navigate(scroll_list[key]), false); //adds event listener and passes the parameter from the object to the function. 
}
// this scrolls to a certain id onclick
function navigate(loc){
 $('html, body').animate({
 scrollTop: $("#"+loc).offset().top
 }, delay2);
} 
asked Sep 11, 2020 at 15:30
1
  • This is probably a question better suited for the main site, but in your addEventListener you're calling the navigate function: navigate(scroll_list[key]). The event handler has the signature event -> void (see this); you need to wrap it in a lambda: (event) => navigate(scroll_list[key]) (in Python it would be: lambda event: navigate(scroll_list[key])). Commented Sep 11, 2020 at 21:32

1 Answer 1

1

The root cause

The following line within your for loop directly invokes the function as you're using the navigate(scroll_list[key]) as the second parameter:

id.addEventListener("click", navigate(scroll_list[key]), false)

The expression says 'call the navigate function right now'.

Setting a reference to the function without calling it

To use a function as an event handler, you need to pass it as a reference (i.e. navigate instead of navigate()):

id.addEventListener("click", navigate, false)

This doesn't directly call the function but only registers it to be called (when element with corresponding id is clicked).

Setting a reference to the function including parameters

If you want to also pass different parameter values (e.g. for each id), you can wrap the target function in an anonymous function:

 id.addEventListener("click", (function () {
 const loc = scroll_list[key];
 return function () {
 navigate(loc)
 }
 })(), false);

Again, this doesn't call the function. It registers it to be called with the desired parameter (the respective id in your case) when the element with corresponding id is clicked.

You've surely noticed that the anonymous function inserted in this step is more complex than the one in the previous option. It's needed to address a specificity in JavaScript.

Variables in JavaScript are scoped to functions, not blocks of code. Hence, to capture the 'current' value of scroll_list[key] at each iteration, we need to store it in a new variable loc wrapped within another anonymous function. Otherwise, the value of scroll_list[key] for any further use (i.e. for use with all event listeners) would stay at the value obtained at last iteration.

answered Sep 11, 2020 at 22:56

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.