2

For some reason I need to loop through various elements and change their style when they are clicked. This is the code(https://jsfiddle.net/wd4z1kvs/1/) I am trying:

var myscroll = {};

myscroll.list = document.getElementsByClassName("navbar-right")[0].getElementsByTagName("li");

for( var j=0; j < 5; j++) {
	myscroll.list[j].anchor = document.getElementsByClassName("navbar-right")[0].getElementsByTagName("li")[j].getElementsByTagName("a")[0];
	myscroll.list[j].anchor.addEventListener("click", function() {
		alert(j);
		myscroll.list[1].anchor.innerHTML = "hello" + j;
                myscroll.list[j].anchor.innerHTML = "yellow" + j;  
	});
}
 <div id="navbar" class="navbar-collapse collapse">
            <ul class="nav navbar-nav navbar-right">
              <li class="active"><a href="#">Home</a></li>
              <li><a href="#artists">Artists</a></li>
              <li><a href="#songs">Songs</a></li>
              <li><a href="#beats">Beats</a></li>
              <li><a href="#contact">Contact</a></li>
            </ul>
          </div>

The problem seems to be that the event works with j's present value. It doesn't take the value of the parameter when the code was actually run.

4

3 Answers 3

1

The simplest solution is to use a forEach, or some other looping callback function:

myscroll.list.forEach(function(item, j) {
    item.anchor = document.getElementsByClassName("navbar-right")[0]
                          .getElementsByTagName("li")[j]
                          .getElementsByTagName("a")[0];
    item.anchor.addEventListener("click", function() {
        alert(j);
        myscroll.list[1].anchor.innerHTML = "hello" + j;
        item.anchor.innerHTML = "yellow" + j;
    });
});
Sign up to request clarification or add additional context in comments.

Comments

1

Try this:

var myscroll = {};

myscroll.list = document.getElementsByClassName("navbar-right")[0].getElementsByTagName("li");

for( var j=0; j < 5; j++) {

  (function(j) {
  
    /* j variable is just a local copy of the j variable from your loop */

    myscroll.list[j].anchor = document.getElementsByClassName("navbar-right")[0].getElementsByTagName("li")[j].getElementsByTagName("a")[0];
	myscroll.list[j].anchor.addEventListener("click", function() {
	
    alert(j);
	
    myscroll.list[1].anchor.innerHTML = "hello" + j;
                myscroll.list[j].anchor.innerHTML = "yellow" + j;  
	});
    
  }(j));
  

  
  
}
<div id="navbar" class="navbar-collapse collapse">
            <ul class="nav navbar-nav navbar-right">
              <li class="active"><a href="#">Home</a></li>
              <li><a href="#artists">Artists</a></li>
              <li><a href="#songs">Songs</a></li>
              <li><a href="#beats">Beats</a></li>
              <li><a href="#contact">Contact</a></li>
            </ul>
          </div>

As noticed @Andreas there is a closure in a loop.

The events don't remember values, they only keep a link (reference) to the environment where they were created. In this case, the variable j happens to live in the environment where the three events were defined. So, all events, when they need to access the value, reach back to the environment and find the most current value of j. After the loop, the j variable's value is 5. So, all five events point to the same value.

4 Comments

I have updated my answer. Here, instead of just creating an event that use j, you pass the j variable's current value to immediate function. In this function, j becomes the local value j, and j has a different value every time.
The IIFE (immediately invoked function expression) creates a new closure for each value of j, so when the event handler executes, it will have access to its own copy of j
@devnull69, exactly.
0

use this: var myscroll = {};

var list = document.getElementsByClassName("navbar-right")[0].getElementsByTagName("li");
myscroll.list = list;

for (var j = 0; j < 5; j++) {
    var anchor = list[j].getElementsByTagName("a")[0];
    anchor.setAttribute("index",j);
    myscroll.list[j].anchor = anchor;
    anchor.addEventListener("click", function () {
        alert(this.getAttribute("index"));
        this.innerHTML = "hello" + this.getAttribute("index");
        //this.innerHTML = "yellow" + this.getAttribute("index");
        this.style.backgroundColor = "yellow";

    });
}

Comments

Your Answer

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.