user8115627 user8115627 - 2 months ago 10
Javascript Question

Create multiple canvases in a loop, only last function gets called

The code below creates multiple canvases with relative input boxes.

The problem is that after running the code only last canvas and its input box are working.



var art = function() {
for (var i = 1; i <= 3; i++) {
var div = document.createElement("div");
var inpbx = document.createElement('input');
var canvas = document.createElement('canvas');
document.getElementById("bx").appendChild(div);
div.appendChild(inpbx);
div.appendChild(canvas);
canvas.style = "border:1px solid gray; height:100px";
var updateCanvas = function() {
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, 300, 300);
ctx.font = "30px Arial";
ctx.fillText(inpbx.value, 10, 50);
};
inpbx.addEventListener("change", updateCanvas, false);
}
};

<button onClick="art()">Do some</button>
<div id="bx"></div>




Answer Source

That's because all functions you create point to the same variable i. Which in the end equals 4. To avoid it you may wrap loop body in a function:

var art = function() {
  for (var i = 1; i <= 3; i++) {
    (function (i) {
      var div = document.createElement('div');
      var inpbx = document.createElement('input');
      var canvas = document.createElement('canvas');

      document.getElementById('bx').appendChild(div);
      div.appendChild(inpbx);
      div.appendChild(canvas);

      canvas.style = 'border:1px solid gray; height:100px';

      var updateCanvas = function() {
        var ctx = canvas.getContext('2d');
        ctx.clearRect(0, 0, 300, 300);
        ctx.font = '30px Arial';
        ctx.fillText(inpbx.value, 10, 50);
      };

      inpbx.addEventListener('change', updateCanvas, false);
    })(i)
  }
};

In ES6 you can just change var i = 1 to let var i = 1.