0

I'm trying to create dynamically a menu in Javascript with a function with one argument in the onclick property using the code bellow:

function createCameraMenu() {
    var nav = document.createElement('nav');
    var ul  = document.createElement('ul');
    ul.className = "menu";

    for (var i = 0; i < cameraID.length; i = i + 1) {
        var liField = document.createElement('li');
        var aField  = document.createElement('a');

        aField.textContent = "CAMERA " + i;

        aField.onclick = function() {
            hideImages(i);
        };

        li.appendChild(aField);
        ul.appendChild(li);
    }

    nav.appendChild(ul);
    document.body.appendChild(nav);
}

and the result should be the code bellow:

<nav>
    <ul class="menu" >
        <li><a href="#" onClick="hideImages(0)">CAMERA 1</a></li>
        <li><a href="#" onClick="hideImages(1)">CAMERA 2</a></li>
        <li><a href="#" onClick="hideImages(2)">CAMERA 3</a></li>                
    </ul>
</nav>

but after creating the menu, for any item clicked, the function hideImages(3) is executed. For some reason, all my functions are created with the same argument (3), that is the value of "i" rejected in the for loop. There is no global var i in my code and I don't know why this is happening. This function is executed in a script tag in the head of the HTML file.

4
  • 1
    Possible duplicate of JavaScript closure inside loops – simple practical example Commented Nov 27, 2015 at 17:08
  • Where is j initialized? Commented Nov 27, 2015 at 17:09
  • 1
    Either add a closure as proposed by A. Wolff or bind hideImages directly: aField.onclick = hideImages.bind(aField, j); Commented Nov 27, 2015 at 17:11
  • "j" was a mistake. Change it to "i". Commented Nov 27, 2015 at 19:44

1 Answer 1

4

You need to use a closure, e.g:

for (var i = 0; i < cameraID.length; i = i++) {
        var liField = document.createElement('li');
        var aField  = document.createElement('a');

        aField.textContent = "CAMERA " + i;

        aField.onclick = (function(i){ return function() {
            hideImages(i);
        };})(i);

        li.appendChild(aField);
        ul.appendChild(li);
    }

Now for readability, you can use a referenced method instead:

aField.onclick = hideImages.bind(aField, i);
Sign up to request clarification or add additional context in comments.

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.