-3

I asked this earlier, got linked to This Thread which didn't really help me what so ever.

I have got a list of instances of a class, these classes store reference to an DOM element, and a method, and an INT.

I need to go through each of these class instances and assign the method to the click event of the elements.

for(var i = 0, l=children.length; i<l; i++) {
      var child = children[i];
      if(child.nodeType === 1 && child.tagName === "LI") {
        listItems[x] = new subMenu(child);
        child.addEventListener('click', function(x) {
          listItems[x].toggle(); <!------- x is always 7, it should be 0-6
        }, false);
        x++;
      }
    }

Below is the class:

class subMenu {
      constructor(obj) {
        this.elm = obj;
        this.state = 0;
      }

      toggle() {
        if (this.state === 0) {
          addClass(this.elm, 'toggled');
          this.state = 1;
        } else {
          removeClass(this.elm, 'toggled');
          this.state = 0;  
        }
      }
    }

Here is an image of the listItems: enter image description here

Edit: If I make the changes I believe to be correct from the linked post, I get this:

var menuParent = document.getElementById('megamenu');
    var children = menuParent.childNodes;
    var x = 0;
    for(var i = 0, l=children.length; i<l; i++) {
      var child = children[i];
      if(child.nodeType === 1 && child.tagName === "LI") {
        listItems[x] = new subMenu(child);
        child.addEventListener('click', bindToggle(x), false);
        x++;
      }
    }
    function bindToggle(i) {
      return listItems[i].toggle();
    }
  }, false);

However the toggle() method is simply running once on assignment and then not running again when I click the element.

Edit 2 Sorry i did actually do it correct the first time, just got the code wrong above. So i have amended my code to return a function to the EventHandler.

var menuParent = document.getElementById('megamenu');
    var children = menuParent.childNodes;
    var x = 0;
    for(var i = 0, l=children.length; i<l; i++) {
      var child = children[i];
      if(child.nodeType === 1 && child.tagName === "LI") {
        listItems[x] = new subMenu(child);
        child.addEventListener('click', bindToggle(x), false);
        x++;
      }
    }
    function bindToggle(x) {
      return function() { console.log("Value: " + x); }; // listItems[x].toggle();
    }

However the console.log is simply outputting

Value: 2

If I add a console.log(x) the line above the EventHandler` then it displays 0-6 like it should, so the value im passing over to the function shouldn't be the issue.

Community
  • 1
  • 1
Martyn Ball
  • 4,679
  • 8
  • 56
  • 126
  • 1
    _"got linked to a thread which didn't really help me what so ever."_ Perhaps mention which one, and why it didn't help, so it doesn't happen again. – James Thorpe Apr 04 '17 at 12:31
  • Sorry, I was linked to this thread but I couldn't associate the code shown there with my individual issue: http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example – Martyn Ball Apr 04 '17 at 12:32
  • It has just been marked as a duplicate by Quentin again, that clearly isn't helping me and im struggling to apply it to my code... – Martyn Ball Apr 04 '17 at 12:33
  • The issue i'm having is if I create an entire function just to assign the toggle() method to the click event, then the function is being executed on assignment, and then executing when I click the element like it should. – Martyn Ball Apr 04 '17 at 12:35
  • 1
    Bottom line, you have a function inside a loop and use a variable within the function that's being modified by the loop. The linked question clearly talks through the issue and what to do about it - take a step back and have a fresh look at it. – James Thorpe Apr 04 '17 at 12:36
  • 1
    "The issue i'm having is if I create an entire function just to assign the toggle() method to the click event, then the function is being executed on assignment, and then executing when I click the element like it should" — That doesn't make a whole lot of sense. Try creating an [mcve] that demonstrates the problem you are having implementing the solutions you were given instead of ignoring those solutions and just repeating the original question. – Quentin Apr 04 '17 at 12:37
  • 1
    The duplicate question has 14 answers that have a score of 10 or more. Just shrugging and saying you don't understand any of them doesn't give anyone much to go on if they want to help you understand. – Quentin Apr 04 '17 at 12:39
  • @Quentin updated my post – Martyn Ball Apr 04 '17 at 12:40

1 Answers1

2

This is the code from the accepted answer on the referenced question:

function createfunc(i) {
    return function() { console.log("My value: " + i); };
}

It returns a function. (The return value is passed to addEventListener).

This is your equivalent code:

function bindToggle(i) {
  return listItems[i].toggle();
}

It just does stuff and then returns nothing (undefined).

Then this code:

child.addEventListener('click', bindToggle(x), false);

Trying to bind undefined as the event handler.

You have to pass a function to addEventListener

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335