0

I'm creating a long list of select items and wanted to create a closure call to add each option, then queue the call (via a setTimer) so the browser would not hang.

My implementation works great, but here is what has me puzzled, the following code:

var mainList = $('#mainList');
for (var i=0;i < 100000; i++) {
  var self = mainList, addOption = function() {
    $(self).append('<option value=' + i + '>' + i + '</option>');
   };

  $.queue.add(addOption, this);
}

generates:

<option value='100000'>100000</option>
<option value='100000'>100000</option>
<option value='100000'>100000</option>  etc...

Where I would like to have it generate the options:

<option value='1'>1</option>
<option value='2'>2</option>
<option value='3'>3</option>  etc...

I'm struggling with how the closure is executed, it makes sense that the addOption() method is called when i == 100000, but I would like the call to reflect the value of i at the time it is queued up.

Is there an easy trick I am missing here?

Mark Kadlec
  • 8,036
  • 17
  • 60
  • 96

2 Answers2

2

Set addOption by IIFE which returns a function

var mainList = $('#mainList');
for (var i = 0; i < 100000; i++) {
    var self = mainList,
        addOption = (function(i) {
            return function() {
                $(self).append('<option value=' + i + '>' + i + '</option>');
            }
        })(i);
    $.queue.add(addOption, this);
}
Community
  • 1
  • 1
AmmarCSE
  • 30,079
  • 5
  • 45
  • 53
  • Pure awesomeness @AmmarCSE, thanks a lot. I'm going to read up on the IIFE and how the js executes right now, that's exactly the functionality I was looking for. – Mark Kadlec Aug 27 '15 at 21:05
2

Prior to the introduction of Function.prototype.bind, it was certainly necessary to employ a closure specifically to trap one or more vars in situations like this.

Now, that approach is considered to be a bit clumsy.

You can define a basic addOption function, then spawn versions of it in the loop, using addOption.bind() to bind in both mainList as "thisArg", and i as the first formal variable :

var mainList = $('#mainList');
var addOption = function(i) {
    this.append('<option value=' + i + '>' + i + '</option>');
};
for (var i=0; i<100000; i++) {
    $.queue.add(addOption.bind(mainList, i), this);
}
Roamer-1888
  • 19,138
  • 5
  • 33
  • 44