1

I am curretly experiencing difficulties implementing an onclick event within a for loop. Instead of alerting the respective value it always returns undefined (presumably a scope problem, because the iteration itself works fine)

Until now I tried to pass on the i variable to the onclick function; however, with little success

for (var i = 0; i < timeSpanLength; i++) {
            // creating the wrap for the month
            var month = document.createElement("div");
            month.className = 'month_element';

            var reference_month = document.createElement("span");
            reference_month.innerHTML = time_span[i];

            //onclick event
            reference_month.onclick = function(i) {
                var month_beginning = signup_date;
                var month_end = time_span[i];
                alert(month_end);
                //searchForData(month_beginning, month_end);
            };

            //append to container
            month.appendChild(reference_month);
            document.getElementById('time_container').appendChild(month);
        }

The expected outcome is to trigger an alert which displays the same month which is displayed in the span element above. I need the variable to pass it on to another function.

Any help is highly appreciated since I am beginner in javascript.

Jakob
  • 195
  • 4
  • 12

2 Answers2

2
for (var i = 0; i < timeSpanLength; i++) {
 (function (index) {
   // creating the wrap for the month
            var month = document.createElement("div");
            month.className = 'month_element';

            var reference_month = document.createElement("span");
            reference_month.innerHTML = time_span[index];

            //onclick event
            reference_month.onclick = function() {
                var month_beginning = signup_date;
                var month_end = time_span[index];
                alert(month_end);
                //searchForData(month_beginning, month_end);
            };

            //append to container
            month.appendChild(reference_month);
            document.getElementById('time_container').appendChild(month);
 })(i);
}
AngelSalazar
  • 3,080
  • 1
  • 16
  • 22
2

This callback function handler is forming a closure with respect to the outer scope. Also var has a function scope, so in essence the block of code can be re-written as:

var i;
for (i = 0; i < timeSpanLength; i++) {
  ...
  //onclick event
  reference_month.onclick = function(i) {
            var month_beginning = signup_date;
            var month_end = time_span[i];
            alert(month_end);
            //searchForData(month_beginning, month_end);
   };
   ...
}

So the var i is hoisted to the top and when the loop completes the value of i is timeSpanLength.length and this is what you use to access time_span[i] and that returns undefined.

Since with var the binding remains the same, the handlers registered will be referring the last value of i in the loop.

So you either need to use let in the for-loop:

for (let i = 0; i < timeSpanLength; i++) { ... }

Or an IIFE which forms a new scope bound to each new value of i from the loop:

for (var i = 0; i < timeSpanLength; i++) { 
   (function(i){
      reference_month.onclick = function(i) {
            var month_beginning = signup_date;
            var month_end = time_span[i];
            alert(month_end);
            //searchForData(month_beginning, month_end);
       };
    })(i) 
}
Fullstack Guy
  • 16,368
  • 3
  • 29
  • 44