Riddle me this: Creating DOM elements in a for loop and attaching events

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • tswaters
    New Member
    • Feb 2007
    • 19

    Riddle me this: Creating DOM elements in a for loop and attaching events

    What a pain. I just pressed "Preview Post" only to find that the server forgot who I was and killed my input. So, where once I had everything described really nice, now I'm just going to write my code and assume everyone is intelligent enough to figure it out:

    [html]
    <html>
    <body onLoad="init(); ">
    <div id="b"></div>
    </body>
    </html>
    [/html]

    [code=javascript]
    function init() {
    var a = test(10,'b');
    a.init();
    alert("I just initialized " + a.buttons + " buttons inside " + a.container.id + "!");
    }

    var test = function( _buttons, _container ) {
    var that=this;

    // public properties
    that.buttons = _buttons;
    that.container = document.getEle mentById(_conta iner);

    // public methods
    that.init = function() {
    for(x=0;x<parse Int(that.button s);x++) {
    var b = document.create Element("INPUT" );
    b.type="button" ; b.id = x; b.value = x;

    /* how best to attach an event? */

    // b.onclick = function() { that.tester(x) }
    // when buttons is clicked, always alerts 10.

    // eval("b.onclick = function() { that.tester('"+ x+"') }")
    // when clicked, alerts correctly, "0-9", but what an ugly hack.

    that.container. appendChild( b );
    }
    }

    that.tester = function( _e ) { alert(_e); }

    return that;
    }
    [/code]

    Anyone know how I can avoid using eval on the event attachment? It will work for strings -- but if I get into objects, maybe as part of a "for x in b" on some data structure I need to turn into dom elements -- I don't think I can pass those in single quotes. If I pass a variable reference, the same reference is used for each attachment in the loop, and it will end up being the last property in the loop for each attachment.... Any suggestions?

    p.s. I don't trust the "this" keyword.
  • acoder
    Recognized Expert MVP
    • Nov 2006
    • 16032

    #2
    I think what you need are closures.

    Comment

    • tswaters
      New Member
      • Feb 2007
      • 19

      #3
      Originally posted by acoder
      I think what you need are closures.
      Hey thanks acoder! Here I didn't even know what they were ... One section in particular very much applied to my post, Closures 1.3: Creating closures in loops: A common mistake

      So when I say,
      [code=javascript]
      that.init = function() {
      ...
      }
      [/code]

      This creates a closure called init ... this includes the environment of the init function, where the variable "x" is defined.... so when the onclick handler is attached, referencing the variable "x":

      [code=javascript]
      b.onclick = function() { that.tester(x) }
      [/code]

      it's looking at the environment from the closure, which at last run, was the last value from the for loop... 10.

      Originally posted by Mozilla Page
      One solution in this case is to use more closures
      This is what I've done:

      [code=javascript]
      b.onclick = callBackTester( x)

      function callBackTester( _e) { return function() { that.tester(_e) ; } }
      [/code]

      And now it works.

      Comment

      • acoder
        Recognized Expert MVP
        • Nov 2006
        • 16032

        #4
        Glad to hear that you got it working!

        Comment

        Working...