eaglehopes Posted July 4, 2023 Share Posted July 4, 2023 (edited) Hi, I prepared a code : <html> <head> <style> .inn { vertical-align: top; display: inline-block; margin: 7px; text-align: left; padding: 10px; border-radius: 30px; text-shadow: 0 0 black; background-color: #ff5722; border-style: solid none none solid; border-width: 5px; border-top-color: red; border-left-color: #ff1800; box-shadow: 4px 4px #7a5858; background-image: linear-gradient(to top, rgba(0,0,0,0) , rgb(255,255,255,.1) ); } .inn:hover { vertical-align: top; color: #4340ff; display: inline-block; padding: 10px; margin: 7px; text-align: left; border-radius: 30px; background-color: #f97950; border-style: solid none none solid; border-width: 5px; border-top-color: #b10000; border-left-color: #910303; box-shadow: 4px 4px #ffffff; background-image: linear-gradient(to top, rgba(0,0,0,0) , rgb(255,255,255,.1) ); } .inText { color : black; } .inn:hover .inText { position : relative ; top : 2px; } .inTextHover { position : relative ; top : 2px; } </style> </head> <body> <div class="navbar"> <div class="inn"> <div class="inText">button1</div> </div> <div class="inn"> <div class="inText">button2</div> </div> <div class="inn"> <div class="inText">button3</div> </div> </div> <script> var toggleButton ; var toggleOn; var btns ; window.addEventListener("load",load); function load() { console.log("loaded?"); btns = Array.from( document.getElementsByClassName("inText") ); // get all buttons to collection object then to an array sessionStorage.setItem("clickCounter",Number(0)); // add click eventlistener to all buttons > loadListeners(btns) ; } function loadListeners(btns) { btns.forEach((item,index,arr) => { item.addEventListener('click',toggleBtn(item,index,arr),false ); }); } function toggleBtn(item,index,arr) { // change botton's class : if(item.className =="inText" ) { // change inText divs' classes console.log("yes"); sessionStorage.setItem("clickCounter",Number(sessionStorage.clickCounter)+1); if(sessionStorage.clickCounter %2 ==1) { item.className="inTextHover"; console.log("click counter : "+sessionStorage.clickCounter); } } } </script> </body> </html> when I load page, I am sawing that, window.load have already triggered the "click" event of divs. Why? I used "addEventListener" function, not a custom function. What is wrong? Thanks. Edited July 4, 2023 by eaglehopes Quote Link to comment Share on other sites More sharing options...
Solution kicken Posted July 4, 2023 Solution Share Posted July 4, 2023 10 minutes ago, eaglehopes said: item.addEventListener('click',toggleBtn(item,index,arr),false ) In that line, you are not assigning the toggleBtn function as an on-click event handler. You are executing that function now and assigning whatever value it returns (which is nothing) as your on-click handler. You need to wrap it an anonymous function which is passed to addEventListener as the click handler. item.addEventListener('click', function(){ toggleBtn(item,index,arr); }, false)  Quote Link to comment Share on other sites More sharing options...
eaglehopes Posted July 4, 2023 Author Share Posted July 4, 2023 (edited) 1 hour ago, kicken said: In that line, you are not assigning the toggleBtn function as an on-click event handler. You are executing that function now and assigning whatever value it returns (which is nothing) as your on-click handler. You need to wrap it an anonymous function which is passed to addEventListener as the click handler. item.addEventListener('click', function(){ toggleBtn(item,index,arr); }, false)  Thanks kicken, actually it worked! However, I think, I did not do anything extra what is done in : w3school example by assigning a function to an event. What is the difference btw mine code and the example code? Is it due to parameters which I supplied to my function ? Edited July 4, 2023 by eaglehopes word correction Quote Link to comment Share on other sites More sharing options...
eaglehopes Posted July 4, 2023 Author Share Posted July 4, 2023 Yes, I found that, it is due to extra parameters I gave... I do not like javascript's "hidden parameter" feature! In other languages there is no such thing, but in javascript, sometimes even I did not sent any parameter, function can have it! function loadListeners() { btns.forEach((item,index,arr) => { console.log("item type is "+typeof(item)); item.addEventListener('click',toggleBtn,false ); }); } function toggleBtn(item) { // write the parameter to console to see what it is ! console.log(item); // it is an PointerEvent whose type is "click" } I changed my code above, and put a parameter named "item" to the toggleBtn functon definition itself (not sent anything inside addEventListener function). I got item as PointerEvent whose type is "click"! I have lot to learn about javascript's these kind of "strange" features. Quote Link to comment Share on other sites More sharing options...
kicken Posted July 4, 2023 Share Posted July 4, 2023 59 minutes ago, eaglehopes said: I do not like javascript's "hidden parameter" feature! There's no hidden parameter feature reference. The issue you have is a very common one among new developers, and that's knowing the difference between a function reference, and executing a function. function myFunction(){ //do stuff } thing.addEventListener('click', myFunction ); //<- pass a reference to myFunction thing.addEventListener('click', myFunction() ); //<- execute myFunction now, pass it's return value. addEventListener wants a callback function, which needs to be passed as a function reference. To do that, you only supply the name of the function (or an inline anonymous function). Adding the parenthesis after the function name causes that function to be executed rather than referenced. When you're passing a function reference, you cannot pass any parameters along with that reference, which is what you were trying to do. In order to supply parameters, you need to use the anonymous inline function as a wrapper. The anonymous function is passed as the real event handler callback, and when the event occurs and the anonymous function is executed, it in turn executes your desired event handler with the proper parameters.  1 Quote Link to comment Share on other sites More sharing options...
eaglehopes Posted July 4, 2023 Author Share Posted July 4, 2023 (edited) I always tried to avoid using "function as wrapper" since, as far as I understood that wrapper code is for more specific situations, not general cases. That was my mistake! Very good explanation ! Thanks kicken, I do not know "pass by reference" and advantage/necessity of using function as wrapper. Edited July 4, 2023 by eaglehopes grammer correction Quote Link to comment Share on other sites More sharing options...
Strider64 Posted July 5, 2023 Share Posted July 5, 2023 (edited) I have been developing an online trivia game for years now and I have finally wrapped this around my head. (Well, at least I think 😂 ) HTML <div id="answers"> <button class="buttonStyle" id="ans1"></button> <button class="buttonStyle" id="ans2"></button> <button class="buttonStyle" id="ans3"></button> <button class="buttonStyle" id="ans4"></button> </div> JavaScript // Function to handle the event when an answer is selected. const pickAnswer = (answerIndex) => { return () => { choice = answerIndex; checkAnswer(); // Only show the next button if the next question exists if (index < triviaData.length - 1) { nextButton.style.display = "block"; // show the next button after an answer is chosen } }; }; // The `startGame` function takes an object as an argument with properties: ans1, ans2, ans3, ans4, id, question. // These properties represent the answers to the current question, the question's id, and the question itself, respectively. const startGame = ({ ans1, ans2, ans3, ans4, id, question }) => { // This line sets the id of the current question to the "data-record" attribute of the element with id "currentQuestion". document.querySelector("#currentQuestion").setAttribute("data-record", id); // This line sets the display number of the current question (index + 1) to the text content of the element with id "currentQuestion". document.querySelector("#currentQuestion").textContent = (index + 1).toString(); // This line sets the text content of the element with id "question" to the question itself. document.querySelector("#question").textContent = question; // This loop iterates over each of the answer buttons. answerButtons.forEach((button, index) => { // This line checks if there was a previous "pickAnswer" event listener attached to the button, // and if so, removes it. const previousPickAnswer = button.__pickAnswer__; if (previousPickAnswer) { button.removeEventListener("click", previousPickAnswer); } // This line creates a new "pickAnswer" event listener, and attaches it to the button. const newPickAnswer = pickAnswer(index + 1); button.addEventListener("click", newPickAnswer, false); button.__pickAnswer__ = newPickAnswer; // This line sets the text content of the button to the corresponding answer (ans1, ans2, ans3, ans4) // with a "📷" character at the beginning. button.textContent = `📷 ${[ans1, ans2, ans3, ans4][index]}` || ""; // If there's no corresponding answer, the button is disabled (its pointer events are set to "none"). // Otherwise, the button is enabled (its pointer events are set to "auto"). if (![ans1, ans2, ans3, ans4][index]) { button.style.pointerEvents = "none"; } else { button.style.pointerEvents = "auto"; } }); }; I comment the script out and I think it's self-explanatory. OK, I'm tired as this is the latest I have stayed up. 🤣 Edited July 5, 2023 by Strider64 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.