开发者

Javascript Array addEventListener

Interactive map with buttons in the shape of states, each button has the state abbreviation as an id, when a button/state is clicked I would like to fire the function "stateSelect" and send the state abbreviation with it so I know what's been pressed. Why doesn't the following work?

    var stateList = new Array("AK","AL","AR","AS","AZ","CA","CO","CT","DC","DE","FL","GA","GU","HI","IA","ID",
    "IL","IN","KS","KY","LA","MA","MD","ME","MH","MI","MN","MO","MS","MT","NC","ND","NE","NH","NJ","NM","NV","NY",
    "OH","OK","OR","PA","PR","PW","RI","SC","SD","TN","TX","UT","VA","VI","VT","WA","WI","WV","WY");

    for (var i = 0; i < stateList.length; i++) {
        document.getElementById(stateList[i]).addEventListener('mousedown', function() {stateSelect(stateList[i])}, false);
    }

I obviously want to avoid 50 some lines of code but I'm 开发者_如何转开发not sure why this simple loop isn't working.


Because when the handler runs, it looks up the value of i, which is wherever it was after the loop finished.

You need to scope the i variable in a function:

function listenerForI( i ) {
    document.getElementById(stateList[i]).addEventListener('mousedown', function() {stateSelect(stateList[i])}, false);
}
for (var i = 0; i < stateList.length; i++) {
    listenerForI( i );
}

Now the i referenced by the handler will be the parameter to the listenerForI function that was invoked. As such, that i will reference the value that was passed in from the for loop.


You have a scoping issue. Javascript is not block-scoped; it is function-scoped. Basically, you must create a new function whenever you wish to create a new variable in a loop.

The most elegant way to do so is as follows:

stateList.map(function(abbrev){
    $(abbrev).mousedown(function(){stateSelect(abbrev)});
});

If you are not using jQuery, merely replace $(abbrev).mousedown with document.getElementById(abbrev).addEventListener.

(Just to preempt the people who go "map isn't standard"; it is in the javascript ECMA-262 standard 5th edition which has support from all browser vendors. If one is paranoid about supporting older browsers, one can just $.map.)

Here is how one would do so using a for loop; it's a bit uglier but it demonstrates the necessity of creating new closures via functions:

for(var i=0; i<stateList.length; i++)
    (function(i){
        $(stateList[i]).mousedown(...);
    })(i);

Like I said, a bit uglier than necessary; you could also do this which is slightly less ugly, but is basically the same thing:

function createListener(abbrev) {
    $(abbrev).mousedown(...);
}
for(var i=0; i<stateList.length; i++)
    createListener(stateList[i]);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜