-3

The GitHub Repository that I have linked will not be used for any other questions (it will not be changed except to help THIS question.... IT WILL ONLY BE USED FOR THIS QUESTION

Note: I have done my research and I believe that my code should work

Ok, so if you require the rest of my code to make a good judgement on this, feel free to go to: My Github Repository which is only going to be used for this 1 question. In the GitHub Repository, there is also a CSS file, but there is no problem with it, just included it so that you can see ALL the code.

Yes, I know that many people on this website do not like it when people include "GitHub" links; however, it is easier for me to explain if I do not have all the code sitting here making a mess (it is easier if I can narrow down what code is giving me an error

Ok, so this "for" loop:

var dropdown = document.getElementsByClassName("dropdown-btn");
  var i;

  for (i = 0; i < dropdown.length; i++) { //this is not getting called for some reason
    dropdown[i].addEventListener("click", something());
    alert("Please work");
  }

is not actually running. When I put an "alert" above the for loop like:

var dropdown = document.getElementsByClassName("dropdown-btn");


 var i;
 alert("This works");
  for (i = 0; i < dropdown.length; i++) { //this is not getting called for some reason
    dropdown[i].addEventListener("click", something());
    alert("This does not work");
  }

The alert is called as soon as the method that the "for" loop is in, is called. I guess to explain my question, is there anything wrong with my "for" loop? (This works in a different .html file, so I am not sure why it is not working in my current workspace.)

UPDATE (February 18, 2019): Ok so I found what is causing the error.

For the person that commented and suggested that I use "console.log(dropdown.length);", this brought up an unexpected error:

function something(){


this.classList.toggle("active");
  var dropdownContent = this.nextElementSibling;
  if (dropdownContent.style.display === "block") {
  dropdownContent.style.display = "none";
  } else {
  dropdownContent.style.display = "block";
  }
}

As I originally said, this works in another file, but for some reason, it says that in "this.classList.toggle("active);", "toggle" is undefined. Is this supposed to be defined in this file, or is it like i think and a default "function"? Through all of my research, and through all the knowledge I have of the language of JavaScript, I am confident that it is a default "function", and unless someone can prove me wrong, I don't understand why this is not working.

Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
Ty Kutcher
  • 25
  • 3
  • 4
    Please post all the relevant code in the question itself, so we have a [MCVE] to debug. Also see [Can we please get the “How to create an MCVE” help page updated, to state that a link to a GitHub project is generally NOT an acceptable MCVE?](https://meta.stackoverflow.com/questions/380194/can-we-please-get-the-how-to-create-an-mcve-help-page-updated-to-state-that-a) – CertainPerformance Feb 18 '19 at 03:20
  • 3
    The `addEventListener()` calls should pass just `something`, not `something()`. – Pointy Feb 18 '19 at 03:21
  • 2
    Also note that unless `something` returns a function, you shouldn't be calling it - just pass it instead. – CertainPerformance Feb 18 '19 at 03:22
  • 2
    The `dropdown.length` is probably 0. Can we see your html Update: I just tried your code in a snippet and it works. Your problem is that there probably isn't a single element with a class of `dropdown-btn` – Aniket G Feb 18 '19 at 03:22
  • 1
    Part of doing your research should consists on put a `console.log(dropdown.length)` just after this code: `var dropdown = document.getElementsByClassName("dropdown-btn");`. Try that and update your question with that info – Shidersz Feb 18 '19 at 03:27
  • "it is easier for me to explain if I do not have all the code sitting here making a mess" , that may be great for you, but it is easier for **us to help you** if the code is on StackOverflow as a [MCVE] so we don't have to go off site then sift through your GitHub. Furthermore if you then purge your repository for future questions, this questions becomes meaningless for anyone else with a similar problem; this is one of the driving factors for StackOverflow. – Jon P Feb 18 '19 at 05:27
  • Furthermore, what errors are you getting in the console? If you're not getting any, explicitly state this. – Jon P Feb 18 '19 at 05:42
  • If there is an error in `something()`, the JavaScript will also stop running before reaching the alert. – Mr Lister Feb 18 '19 at 07:41
  • 2
    Please don't edit UPDATED or anything like that to the title. Those interested can see that you've edited it by looking at the date it was modified. Also, adding words in bold, italic, and all caps is unlikely to persuade others your words carry any weight. – Heretic Monkey Feb 18 '19 at 22:18
  • 1
    Whether `classList.toggle` is a function or not depends heavily on what `this` is in the context of that line of code. If it is an `Element` or descendant, then [it is a DOM property and method](https://developer.mozilla.org/en-US/docs/Web/API/Element/classList#Methods). Without seeing how the code is called, I couldn't tell you why it's not working. – Heretic Monkey Feb 18 '19 at 22:26
  • "this.classList.toggle("active);", "toggle" is undefined. - I don't know if that typo because of misplaced quotes is in your code or in your question only. If you fix the quotes and still get the error, try `console.log( this );` – JasonB Feb 19 '19 at 02:04

4 Answers4

3

The problem is that you are passing a function in as a parameter without wrapping it in a calling function.

There are two ways you would make this work.

  1. Remove the () from the something function and call the alert inside of something
    for (i = 0; i < dropdown.length; i++) { //this is not getting called for some reason
      dropdown[i].addEventListener("click", something)
    }

    something () {
      alert('this is working')
      ...
    }
  1. Put a single function call in your event handler and place both function calls inside
    for (i = 0; i < dropdown.length; i++) { //this is not getting called for some reason
      dropdown[i].addEventListener("click", function () {
        something();
        alert("This works");
      })
    }

Here is an example:

doğukan
  • 23,073
  • 13
  • 57
  • 69
Miguel Coder
  • 1,896
  • 19
  • 36
2

You are calling something instead of just passing the callable function when trying to add the eventListener. Remove the parentheses.

var dropdown = document.getElementsByClassName("dropdown-btn");
  var i;

  for (i = 0; i < dropdown.length; i++) { //this is not getting called for some reason
    dropdown[i].addEventListener("click", something);
  }
  
  function something() {
    this.classList.toggle("active");
    var dropdownContent = this.nextElementSibling;
    if (dropdownContent.style.display === "block") {
    dropdownContent.style.display = "none";
    } else {
    dropdownContent.style.display = "block";
    }
  }
<a class="dropdown-btn" href="#">Button 1</a>
<div style="display:none;">Dropdown Content Here</div>
<br />
<a class="dropdown-btn" href="#">Button 2</a>
<div style="display:none;">Dropdown Content Here</div>
JasonB
  • 6,243
  • 2
  • 17
  • 27
  • While *helpful*, this will not fix the fundamental iteration problem - his code never gets to `alert("This does not work");`, so the line above it that adds the listener does not run either. (either that, or `something` throws an error), sounds likely that nothing exists in the collection – CertainPerformance Feb 18 '19 at 03:27
  • True, but the ops real fundamental problem is not providing a minimal, runnable example demonstrating the issue. I have seen this kind of "non-answer answer" help others in the past by demonstrating that the code works and that it is other conditions in the system that are the issue. – JasonB Feb 18 '19 at 03:33
  • 1
    Requests for clarification ("there is not enough information to say what the actual problem is") should be *comments*, not answers. – CertainPerformance Feb 18 '19 at 03:39
  • @CertainPerformance if you check the github repo you would know that something DOES exist in the collection. The html page does have elements with the selected class. – Miguel Coder Feb 18 '19 at 03:44
  • 1
    @MiguelCoder Questions are expected to be complete, with all information necessary in the question itself for this reason (among others). – Heretic Monkey Feb 18 '19 at 22:20
  • That's understandable, but he did mention the existence of his repo. That's all I'm saying. – Miguel Coder Feb 18 '19 at 22:22
  • Updated this snippet to include the contents of the "something" function which shows that when you call it this way it works as expected - only tested in Chrome. – JasonB Feb 19 '19 at 02:02
1

I was watching the repository on GitHub, and I saw that there are a lot of errors in your html part, so that the JS part can not work.

Just about this loop, the current html part is:

<button class="dropdown-btn" onclick="drop()">OUR STORY 
  <i class="fa-caret-down"></i>
</button>

So that the first time the drop () function creates a new event listener on the button, but does not call it. If there is a second click on this button then 2 actions are then launched: the first adds again a new event listener click on the button, the second is the triggering of the event listener created the first time.

There are 2 possible solutions

Solution 1

<button class="dropdown-btn" onclick="something()">OUR STORY 
  <i class="fa-caret-down"></i>
</button>    

Solution 2

<button class="dropdown-btn" >OUR STORY 
  <i class="fa-caret-down"></i>
</button>

With in the part JS = ( ! remove function drop() declaration ! )

var dropdown = document.getElementsByClassName("dropdown-btn");

for (let i = 0, iMax=dropdown.length ; i < iMax ; i++) {
  dropdown[i].addEventListener("click", something);
}

for helping understand why your code is wrong, please try this sample code

var Compteur = 0;


function something(){
  console.log('call on something()', ++Compteur);
}


function drop(){
  var dropdown = document.getElementsByClassName("dropdown-btn");

  for (let i = 0; i < dropdown.length; i++) { 
    dropdown[i].addEventListener("click", something);
    console.log( 'adding event Listener on one dropdown-btn ', ++Compteur);
  }
}
<button class="dropdown-btn" onclick="drop()">OUR STORY </button>
Mister Jojo
  • 20,093
  • 6
  • 21
  • 40
  • no, you plenty of other errors, first one one is about => https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded – Mister Jojo Feb 19 '19 at 16:13
  • **Solution 1** won't work without rewriting the function ..... https://jsfiddle.net/3a45jkcf/ – Jon P Feb 20 '19 at 22:16
  • yes, it is possible, but this answer is just an indication of how to code that, I never intended to give a complete solution because there are many other errors elsewhere in its code , as I already mentioned here – Mister Jojo Feb 20 '19 at 23:41
1

Here is your problem.

Ask yourself why are you getting this.classList as undefined?

If you looked further you would find that this is the window object which has no classList . Now ask yourself why the window object?

It is because something() is an event listener that should be called in response to an event. In the line dropdown[i].addEventListener("click", something()); , you aren't assigning something() as an event handler, you are calling the method, without an event, so there is no this.classList as this is the window object.

As other answers have mentioned you need to change this to:

dropdown[i].addEventListener("click", something);

Which will assign the event something() to the click event, without calling it.

Complete Example

function something(){
  console.log(this); //For Debug prurposes
  this.classList.toggle("active");
  var dropdownContent = this.nextElementSibling;
  if (dropdownContent.style.display === "block") {
  dropdownContent.style.display = "none";
  } else {
  dropdownContent.style.display = "block";
  }
}


/* Loop through all dropdown buttons to toggle between hiding and showing its dropdown content - This allows the user to have multiple dropdowns without any conflict */
function drop(){
  var dropdown = document.getElementsByClassName("dropdown-btn");
  var i;

  for (i = 0; i < dropdown.length; i++) { //this is not getting called for some reason
    dropdown[i].addEventListener("click", something);
    console.log("Please wokrk");
  }
}
.sidenav a, .dropdown-btn {
  padding: 6px 8px 6px 16px;
  text-decoration: none;
  font-size: 20px;
  color: #818181;
  display: block;
  border: none;
  background: none;
  width: 100%;
  text-align: left;
  cursor: pointer;
  outline: none;
}

.active {
  background-color: green;
  color: white;
}

.dropdown-container {
  display: none;
  background-color: #262626;
  padding-left: 8px;
}
<button class="dropdown-btn" onclick="drop()">OUR STORY 
    <i class="fa-caret-down"></i>
  </button>
  <div class="dropdown-container">
    <a href="#about_us">ABOUT US</a>
    <a href="#community">COMMUNITY</a>
    <a href="#">HUMANITARIAN ACTION</a>
  </div>

On a side note, it is quite unusual to use inline events like onClick=drop() to then bind other event listeners to the same element. It is actually best practice to avoid inline javascript all together.

In the future, please include all code relevant to the question, in the question itself. As I mentioned in a comment it makes it easier for us to help you.

Jon P
  • 19,442
  • 8
  • 49
  • 72
  • Thank you, after going through all the answers, this was the first one that actually made a difference – Ty Kutcher Feb 19 '19 at 20:33
  • this code snippet is also wrong. I changed my previous post to explain why with a new code snippet – Mister Jojo Feb 20 '19 at 05:45
  • @MrJ, please explain further how my code snippet is wrong. – Jon P Feb 20 '19 at 05:51
  • Please try my sample code( on the end of my post), they show each call on functions drop() and something() . you will see that function something() is not called the first time, and this is why he wrote : this is not getting called. And after they repeat to create new addeventListener on each click – Mister Jojo Feb 20 '19 at 05:56
  • @MrJ , I disagree. The original question seemed to based around the assumption that the `for` loop was not executing, because `alert("Please work");` never executed. This is an incorrect assumption, as I have outlined in this answer, because `something()` was being called and not assigned, this resulted in the error of `this` being undefined. I also stated in the answer that is is unusual to bind event listeners in this way. There is nothing in the question that indicates `something()` should be bound on page load. – Jon P Feb 20 '19 at 06:05
  • The initial question was wrong because it did not reflect the reality of its code placed on GitHub, on which I based my answer. I saw in your example code that you have used some of the GitHub code yourself since you put the `onclick =" drop () "` which is precisely at the root of his problem of the false misfire. execution of its for loop, while it thinks that the addeventListener is the equivalent of a direct call of the something () function. And your code Snippet do the same error. – Mister Jojo Feb 20 '19 at 06:15
  • @MrJ "The initial question is wrong"? How can this actually be? Sure, Ty has a misunderstanding of his code and what is happening, but that does not make the question wrong. My answer elaborates on how to debug the *initial* problem and resolve the *initial* problem. Perhaps Ty wants to add an additional event listener as the result of an initial click, perhaps not, we don't know. I also point out that the pattern he is using is quite unusual. My code executes without error and resolves the problem as asked and makes no further assumptions. – Jon P Feb 20 '19 at 22:04
  • The code posted on StackOverFlow and the one on GitHub are different and are subject to incompatible questions. And as he explains that his complete code and reference for him is the one present on GitHub, it means that his code posted here is wrong, which in total gives a wrong question. – Mister Jojo Feb 20 '19 at 23:36
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/188774/discussion-between-jon-p-and-mrj). – Jon P Feb 20 '19 at 23:46