Uncaught ReferenceError: I am not defined

I am trying to create a for-loop base on my array

var lists = [ "a", "b", "c", "d" ];


Js

 for ( i = 0; i < lists.length; i++) { // console.log(lists[i]); $(".sa-report-btn-"+lists[i] ).click(function () { $(".sa-hide-"+lists[i]).removeClass("hidden"); $(".sa-report-"+lists[i]).addClass("hidden"); }); $(".sa-hide-btn-"+lists[i]).click(function () { $(".sa-hide-"+lists[i]).addClass("hidden"); $(".sa-report-"+lists[i]).removeClass("hidden"); }); } 

Am I doing it right? I got an Uncaught ReferenceError: i is not defined Can I concatenate each loop using the jQuery selector as follows → $(".sa-hide-"+lists[i]) ? just curious...

+7
javascript jquery
source share
1 answer

First of all, it looks like you are using strict mode - good ! This saved you from falling prey to the horror of implicit globals .

There are two problems in the code.

First, you are missing a declaration for i . You need to add var i; above the loop, for example:

 var i; for ( i = 0; i < lists.length; i++) { // ... 

or

 for (var i = 0; i < lists.length; i++) { 

Note that even in this last example, the variable i is functional, not limited to the for loop.

The second is more subtle and outlined in this question and its answers : Your click handlers will have a strong link to the i variable, and not a copy from the place they were created. Therefore, when they start in response to a click, they will see i as the value of lists.length (the value that it has when the loop is completed).

In your case, this is very easy to fix (and you no longer need to declare i ): completely remove the loop and replace it with Array#forEach or jQuery.each :

 lists.forEach(function(list) { $(".sa-report-btn-" + list).click(function () { $(".sa-hide-" + list).removeClass("hidden"); $(".sa-report-" + list).addClass("hidden"); }); $(".sa-hide-btn-" + list).click(function () { $(".sa-hide-" + list).addClass("hidden"); $(".sa-report-" + list).removeClass("hidden"); }); }); 

If you need to support really old browsers, you can either shim Array#forEach (which was added in 2009 as part of ECMAScript5), or you can use $.each ( jQuery.each ) instead:

 $.each(lists, function(index, list) { // Note addition ------^ $(".sa-report-btn-" + list).click(function () { $(".sa-hide-" + list).removeClass("hidden"); $(".sa-report-" + list).addClass("hidden"); }); $(".sa-hide-btn-" + list).click(function () { $(".sa-hide-" + list).addClass("hidden"); $(".sa-report-" + list).removeClass("hidden"); }); }); 

Note that we do not actually use index anywhere in our callback, but we must specify it because $.each calls our callback with the index as the first argument and the value as the second. (That's why I prefer Array#forEach .) Thus, we have to accept two arguments, the one we want to be second.

+16
source share