Jerielle
Jerielle

Reputation: 7520

How to call a jquery event trigger while using a loop?

I have a problem in dealing with my problem. My problem is I am creating a static navigation. That uses trigger event. Because I am displaying a simple collapsible div. What I did is I include all my id name in an array and I loop it to create an event. But when I click a link i doesn't call my jquery event. Is there a way how can I prevent hard coded of navigation?

Here's my sample code:

var toggleState = true;
var header_name = ["ParentA", "ParentB", "ParentC", "ParentD"];
var child_name = ["ChildA", "ChildB", "ChildC", "ChildD"];

for (var x = 0; x < header_name.length; x++) {
    $("#" + header_name[x]).click(function (e) {
        if (toggleState) {
            $("#" + child_name[x]).show("slide");
        } else {
            $("#" + child_name[x]).hide("slide");
        }
        toggleState = !toggleState;
    });
}
<div id="ParentA">Click A</div>
<div id="ChildA" style="display: none">Child A</div>
<div id="ParentB">Click A</div>
<div id="ChildB" style="display: none">Child B</div>
<div id="ParentC">Click A</div>
<div id="ChildC" style="display: none">Child C</div>

Here's the fiddle: http://jsfiddle.net/rochellecanale/cveze/3/

Upvotes: 1

Views: 233

Answers (3)

Arun P Johny
Arun P Johny

Reputation: 388446

If you can make minor changes to the html it should be as simple as

<div id="ParentA" class="click-toggle" data-target="#ChildA">Click A</div>
<div id="ChildA" style="display: none">Child A</div>
<div id="ParentB" class="click-toggle" data-target="#ChildB">Click B</div>
<div id="ChildB" style="display: none">Child B</div>
<div id="ParentC" class="click-toggle" data-target="#ChildC">Click C</div>
<div id="ChildC" style="display: none">Child C</div>

then

$(document).ready(function(){
    $('.click-toggle').click(function () {
        $($(this).data('target')).stop(true, true).slideToggle();
    })
});

Demo: Fiddle

or even

<div id="ParentA" class="click-toggle">Click A</div>
<div id="ChildA" style="display: none">Child A</div>
<div id="ParentB" class="click-toggle">Click B</div>
<div id="ChildB" style="display: none">Child B</div>
<div id="ParentC" class="click-toggle">Click C</div>
<div id="ChildC" style="display: none">Child C</div>

then

$(document).ready(function(){
    $('.click-toggle').click(function () {
        $(this).next().stop(true, true).slideToggle();
    })
});

Demo: Fiddle, if you want to maintain left -> right slide: Fiddle

to make your code work... the main problem is the use of shared closure variable toggleState... each menu item should have its own state variable... the solution is to create a private closure for each one

$(document).ready(function () {
    var header_name = ["ParentA", "ParentB", "ParentC", "ParentD"];
    var child_name = ["ChildA", "ChildB", "ChildC", "ChildD"];
    $.each(header_name, function (idx, id) {
        var toggleState = true;
        $('#' + id).click(function () {
            if (toggleState) {
                $("#" + child_name[idx]).show("slide");
            } else {
                $("#" + child_name[idx]).hide("slide");
            }
            toggleState = !toggleState;
        })
    })
});

Demo: Fiddle

Upvotes: 1

McGarnagle
McGarnagle

Reputation: 102793

You need to create a local copy of x for each iteration of the loop. The simplest way to do this is to create a helper function like getClickHandler:

function getClickHandler(x) {
    return function(e){
            if(toggleState){
                $("#" + child_name[x]).show("slide");
            }else{
                $("#" + child_name[x]).hide("slide");
            }
            toggleState = !toggleState;
          };
}

for(var x = 0; x < header_name.length; x++){
    $("#" + header_name[x]).click(getClickHandler(x));
}

The key point here is that the function inside click runs at a later time (asynchronously). Because of how variable scope works in Javascript, your code passes the same reference to x in to each handler, which is why all of them end up getting the last iteration of the array. Doing the above creates a copy of x at the current iteration, and stores it in a local reference (inside the handler function).

Upvotes: 2

Marty Cortez
Marty Cortez

Reputation: 2343

change this:

var header_name = ("Parent A", "Parent B", "Parent C", "Parent D"); 

to this

var header_name = ["Parent A", "Parent B", "Parent C", "Parent D"];

likewise with the next variable

Upvotes: 2

Related Questions