Loop fixing

I'm going through JavaScript: The Definitive Guide by David Flanagan and I'm stuck with the following example:

window.onload = function() {
    var elements = document.getElementsByClassName("reveal");
    for(var i = 0; i < elements.length; i++) {
        var elt = elements[i];
        var title = elt.getElementsByClassName("handle")[0];
        title.onclick = function() {
            if(elt.className == "reveal") elt.className = "revealed";
            else if(elt.className == "revealed") elt.className = "reveal;"
        }
    }
};

<div class="reveal">
    <h1 class="handle">Click Here to Reveal Hidden Text</h1>
    <p>This paragraph is hidden. It appears when you click on the title.</p>
</div>

      

The problem is that the code in its current form works, but if I have to add more than one div

with a class reveal

, no matter which element h1

I click, only the last one will expand. What should I change in the code to make it work on separate divs?

PS I understand that this question is asked quite often due to the nature of the loop closure problem, but I can't get my code work to get solutions to similar questions on SO. Thank.

+3


source to share


1 answer


In JavaScript, the scope of a variable is set to... Functions create closures that essentially define the boundaries of an area. the child scope can access variables defined in the parent scope , but not vice versa.

When you call a handler function onclick

, it should search up the chain of chainsto find the variable elt

because it is elt

not declared within the current scope.

The next level in the scope chain is your handler function window.onload

(i.e., closure). In this area, the variable elt

is declared , and its value is given cycle. But remember, when you click <h1>

and call the handler onclick

, the loop is already over . Therefore, elt

it will always be the last value set in the loop. This is why you always receive elt

as the last item.



To fix this problem, you can use the immediate execution function . The immediate function creates a new closure (and scope) where it is elt

declared locally. Since the variable is elt

now declared in this new inner scope, it is not modified by the loop in the parent scope:

window.onload = function() {
    var elements = document.getElementsByClassName("reveal");
    for(var i = 0; i < elements.length; i++) {
        var elt = elements[i];
        var title = elt.getElementsByClassName("handle")[0];
        title.onclick = (function(elt) {
            return function() {
                if(elt.className == "reveal") elt.className = "revealed";
                else if(elt.className == "revealed") elt.className = "reveal;"
            };
        })(elt);
    }
};

      

+4


source







All Articles