9

I have a series of divs in a pattern of header/body, where a click on the header will show the body in question.

This all happens with .click initialized on page ready...

Rather than doing this (which works fine, but is a pain):

$('#show_fold_ping').click(function(){ ShowArea('#fold_ping') });
$('#show_fold_http').click(function(){ ShowArea('#fold_http') });
$('#show_fold_smtp').click(function(){ ShowArea('#fold_smtp') });
$('#show_fold_pop3').click(function(){ ShowArea('#fold_pop3') });
...

I am trying to do this:

var Areas = ['ping','http', 'smtp', 'pop3'];

for( var i in Areas ){
    Area = '#show_fold_'+Areas[i];
    $(Area).click(function(){ alert(Area); /* ShowArea(Area); */ });
}

The problem I'm having is that ALL of them seem to be initialized to the last one. IE: If pop3 is the last one, a click on #show_fold_[any] will alert '#show_fold_pop3'.

This seems like it should be really simple. Am I missing something obvious, or is there an issue with passing a string to jQuery that I don't know about?

Edit:

Hey, these are all great. I have read up a bit on closures and self-invoking functions, and (kindasorta) get it.

So far, I have this, but the click doesn't seem to be binding correctly. Area will alert with the correct value, but no click bind. Am I still having scope issues with Area, or am I just totally off mark?

$(function(){

    Areas = ['ping','http', 'smtp', 'pop3', 'imap', 'ftp', 'dns', 'tcp', 'database', 'seo'];

    for( var i = 0; i < Areas.length; i++ ){
        (function (Area) {
                            alert(Area);
            $("#show_fold_"+Area).click(function(){ alert('x'); });
        })(Areas[i]);
    }
});
2
  • Shouldn't $("#fold_"+Area).click(...) be $("#show_fold_"+Area).click(...)? Commented Jan 30, 2009 at 3:33
  • Yes! Thank you - that's it. So focused on the syntax I went semantically blind =o) Commented Jan 30, 2009 at 8:20

4 Answers 4

12

Yes, I have run into this problem all too often. Area is a global variable since it does not have var before it. Also, don't use a for...in construct.

But you might still run into a similar problem. God knows how many scripts I've debugged because of a similar bug. Doing the following guarantees proper scoping:

var Areas = ['ping','http', 'smtp', 'pop3'];

for( var i = 0; i < Areas.length; i++ ){
  (function(area) {
    $(area).click(function(){ alert(area); /* ShowArea(area); */ });
  })(Areas[i]);
}
Sign up to request clarification or add additional context in comments.

Comments

3

It's a JavaScript thing; it's not jQuery related. What you're doing is creating a closure, but you're not understanding properly how they work.

You might want to read up on http://blog.morrisjohns.com/javascript_closures_for_dummies, especially Examples 5, 6, and 7.

Comments

2

Check the scope of your "Area" variable. You're basically assigning a global variable so on the last iteration "Area" is scoped outside of the loop.

Comments

1

be sure that you added the click event handling after the DOM has been loaded you can include this on the head element:

var Areas = ['ping','http', 'smtp', 'pop3'];

$(document).ready(function() {
    $.each(Areas, function(i, v){
        var Area = '#show_fold_' + v;
        $(Area).click(function() {
            alert(Area);
        });
    });
}

1 Comment

You might want to edit that script. var Area in Areas and Area = ... + Areas[i]?

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.