Getting an iterated local variable into a closure

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Getting an iterated local variable into a closure

panyasan
Hello,

this is a JavaScript question, but one that I bump into once in a while when developing with qooxdoo.

Test the following code in the playground:

var vbox = new qx.ui.container.Composite( new qx.ui.layout.VBox(5));
this.getRoot().add(vbox);
var data = {
  "one": { label: "One" },
  "two" : { label: "Two" },
  "three":{ label: "Three" },
  "four":{ label: "Four" },
  "five":{ label: "Five" }
};

for( var key in data )
{
  var button = new qx.ui.form.Button( data[key].label );
  vbox.add(button);
 
  // this doesn't work
  button.addListener("execute",function(){
    alert("Bad:" + data[key].label);
  },this);
 
  // this works but is a nasty hack
  eval('button.addListener("execute",function(){'+
    'alert("Good:"+data["'+ key+ '"].label);'+
  '},this);');
}

What I am trying to achieve is to get a local variable ('key') that is the product of the iteration through the keys of an object into a closure (here: an event listener). The problem is that when the event listener is called, the variable "key" evaluates to the last value it had when the iteration was completed, not to the value it had when the even listener was created. The only solution I could come up after a lot of experimenting was to use an ugly eval. Does anyone have a better idea?

Thanks,

Christian
Reply | Threaded
Open this post in threaded view
|

Re: Getting an iterated local variable into a closure

Derrell Lipman
On Sun, Oct 25, 2009 at 20:39, panyasan <[hidden email]> wrote:

What I am trying to achieve is to get a local variable ('key') that is the
product of the iteration through the keys of an object into a closure (here:
an event listener). The problem is that when the event listener is called,
the variable "key" evaluates to the last value it had when the iteration was
completed, not to the value it had when the even listener was created. The
only solution I could come up after a lot of experimenting was to use an
ugly eval. Does anyone have a better idea?

var vbox = new qx.ui.container.Composite( new qx.ui.layout.VBox(5));
this.getRoot().add(vbox);
var data = {
 "one": { label: "One" },
 "two" : { label: "Two" },
 "three":{ label: "Three" },
 "four":{ label: "Four" },
 "five":{ label: "Five" }
};

for( var key in data )
{
 var button = new qx.ui.form.Button( data[key].label );
 vbox.add(button);

 // this doesn't work
 button.addListener("execute",function(){
   alert("Bad:" + data[key].label);
 },this);
  
 (function()
  {
    var thisKey = key;
    button.addListener("execute", function(){
      alert("Good:" + data[thisKey].label);
    },this);
  })();
}

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
qooxdoo-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel
Reply | Threaded
Open this post in threaded view
|

Re: Getting an iterated local variable into a closure

Petr Kobalíček
I'm preferring this way instead of closures:

for( var key in data )
{
 var button = new qx.ui.form.Button( data[key].label );
 button.setUserData("id", key);
 vbox.add(button);

 button.addListener("execute",function(ev){
   alert("Bad:" + data[ev.getTarget().getUserData("id")].label);
 },this);
}

Not tested, maybe there is bug in code, but logically is should be ok.

2009/10/26 Derrell Lipman <[hidden email]>:

> On Sun, Oct 25, 2009 at 20:39, panyasan <[hidden email]> wrote:
>>
>> What I am trying to achieve is to get a local variable ('key') that is the
>> product of the iteration through the keys of an object into a closure
>> (here:
>> an event listener). The problem is that when the event listener is called,
>> the variable "key" evaluates to the last value it had when the iteration
>> was
>> completed, not to the value it had when the even listener was created. The
>> only solution I could come up after a lot of experimenting was to use an
>> ugly eval. Does anyone have a better idea?
>
> var vbox = new qx.ui.container.Composite( new qx.ui.layout.VBox(5));
> this.getRoot().add(vbox);
> var data = {
>  "one": { label: "One" },
>  "two" : { label: "Two" },
>  "three":{ label: "Three" },
>  "four":{ label: "Four" },
>  "five":{ label: "Five" }
> };
>
> for( var key in data )
> {
>  var button = new qx.ui.form.Button( data[key].label );
>  vbox.add(button);
>
>  // this doesn't work
>  button.addListener("execute",function(){
>    alert("Bad:" + data[key].label);
>  },this);
>
>  (function()
>   {
>     var thisKey = key;
>     button.addListener("execute", function(){
>       alert("Good:" + data[thisKey].label);
>     },this);
>   })();
> }
>
> ------------------------------------------------------------------------------
> Come build with us! The BlackBerry(R) Developer Conference in SF, CA
> is the only developer event you need to attend this year. Jumpstart your
> developing skills, take BlackBerry mobile applications to market and stay
> ahead of the curve. Join us from November 9 - 12, 2009. Register now!
> http://p.sf.net/sfu/devconference
> _______________________________________________
> qooxdoo-devel mailing list
> [hidden email]
> https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel
>
>



--
Best regards
- Petr Kobalicek <http://kobalicek.com>

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
qooxdoo-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel
Reply | Threaded
Open this post in threaded view
|

Re: Getting an iterated local variable into a closure

Fabian Jakobs
Administrator
In reply to this post by panyasan
panyasan schrieb:

> Hello,
>
> this is a JavaScript question, but one that I bump into once in a while when
> developing with qooxdoo.
>
> Test the following code in the playground:
>
> var vbox = new qx.ui.container.Composite( new qx.ui.layout.VBox(5));
> this.getRoot().add(vbox);
> var data = {
>   "one": { label: "One" },
>   "two" : { label: "Two" },
>   "three":{ label: "Three" },
>   "four":{ label: "Four" },
>   "five":{ label: "Five" }
> };
>
> for( var key in data )
> {
>   var button = new qx.ui.form.Button( data[key].label );
>   vbox.add(button);
>  
>   // this doesn't work
>   button.addListener("execute",function(){
>     alert("Bad:" + data[key].label);
>   },this);
>  
>   // this works but is a nasty hack
>   eval('button.addListener("execute",function(){'+
>     'alert("Good:"+data["'+ key+ '"].label);'+
>   '},this);');
> }
>  

I usually use qx.lang.Function.bind:

for( var key in data )
{
  var button = new qx.ui.form.Button( data[key].label );
  vbox.add(button);
 
  // this doesn't work
  button.addListener("execute", qx.lang.Function.bind(function(key){
    alert("Good:" + data[key].label);
  }, this, key));
}


This creates a wrapped function in place and binds the first parameter
to the current value of key.

Best Fabian

--
Fabian Jakobs
JavaScript Framework Developer

1&1 Internet AG - Web Technologies
Ernst-Frey-Straße 9 · DE-76135 Karlsruhe
Telefon: +49 721 91374-6784
[hidden email]

Amtsgericht Montabaur / HRB 6484
Vorstände: Henning Ahlert, Ralph Dommermuth, Matthias Ehrlich, Thomas Gottschlich, Robert Hoffmann, Markus Huhn, Hans-Henning Kettler, Dr. Oliver Mauss, Jan Oetjen
Aufsichtsratsvorsitzender: Michael Scheeren


------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
qooxdoo-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel
Reply | Threaded
Open this post in threaded view
|

Re: Getting an iterated local variable into a closure

panyasan

Fabian Jakobs wrote
I usually use qx.lang.Function.bind:

for( var key in data )
{
  var button = new qx.ui.form.Button( data[key].label );
  vbox.add(button);
 
  // this doesn't work
  button.addListener("execute", qx.lang.Function.bind(function(key){
    alert("Good:" + data[key].label);
  }, this, key));
}

This creates a wrapped function in place and binds the first parameter
to the current value of key.
Cool, that's exactly what I need. Thanks for all the suggestions - I'll pick the most qooxdoo'ish. Maybe a good addition to the snippet section.

Thanks,
Christian
Reply | Threaded
Open this post in threaded view
|

Re: Getting an iterated local variable into a closure

Derrell Lipman
In reply to this post by Fabian Jakobs
On Mon, Oct 26, 2009 at 05:05, Fabian Jakobs <[hidden email]> wrote:
button.addListener("execute", qx.lang.Function.bind(function(key){
   alert("Good:" + data[key].label);
 }, this, key));
}


This creates a wrapped function in place and binds the first parameter
to the current value of key.


I like Fabian's solution better than the one I posted.

Derrell
 

------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
qooxdoo-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel