Your Universal Remote Control Center
RemoteCentral.com
Philips Pronto Professional Forum - View Post
Previous section Next section Up level
Up level
The following page was printed from RemoteCentral.com:

Login:
Pass:
 
 

Topic:
Problem with clossure
This thread has 10 replies. Displaying all posts.
Post 1 made on Tuesday November 30, 2010 at 11:26
krissie
Lurking Member
Joined:
Posts:
November 2010
4
Hello,

I'm creating a script to control the lights in my house using some cheap RF thingies and an arduino attached to a server running a mysql database.

I can turn on/off the lights by browsing to a page, e.g.: [Link: 192.168.0.120]

I have created page with a couple of buttons; and now want to attach this command to the buttons (with each button having a different unitid ofcourse).

Here is my code:

function ParseData(data) 
{
   actors = eval(data);

   for (i = 0; i < actors.length; i++) 
   {
      CF.widget("LBL_DESC_" + (i+1)).label = actors[i].description;
      var color;
      actors[i].state > 0 ? color = 0x00ffff : color = 0xffffff;
      CF.widget("LBL_ICON_" + (i+1)).color = color;
      SetLineVisibility((i+1), true);
 
 var pon = function(id) 
 {
return function()
{
System.print("pon = " + id);
}
 }(actors[i].id);
  
 CF.widget("BTN_ON_" + (i+1)).onPress = pon;
   }
}

The ParseData function is the callback which is executed whenever I have retrieved some JSON-code from the mysql database.

Whenever I run this script on the CP, I get the following error message:
ProntoScript error: ReferenceError: id is not defined
Offending page script: (untagged)
Offending line #40: "System.print("pon = " + id);"

What is wrong with this code ?
The 'id' value is valid in the outer loop of the closure, because I can do a printf of it ...


Any ideas ?

Thanks in advance !
Kris
Post 2 made on Tuesday November 30, 2010 at 14:29
BluPhenix
Long Time Member
Joined:
Posts:
December 2008
371
Wow this is some odd looking code.

in javascript don't define vars in loops, it makes the code harder to read. Declare all the variables that will be used in the funcion at the beginning of the function, as variables in javascript are function-wide, not closure-wide.

function ParseData(data) {
    actors = eval(data);
    for (i = 0; i < actors.length; i++) {
        CF.widget("LBL_DESC_" + (i+1)).label = actors[i].description;
        var color;
        actors[i].state > 0 ? color = 0x00ffff : color = 0xffffff;
        CF.widget("LBL_ICON_" + (i+1)).color = color;
        SetLineVisibility((i+1), true);
 
        var pon = function(id) {
            return function() {
                System.print("pon = " + id);
            }
        } (actors[i].id);
        CF.widget("BTN_ON_" + (i+1)).onPress = pon;
    }
}

I rearranged it a bit so i't easyer to read. Are you sure this is what you wanted to write?

- actors is an implied global variable.
- i is an implied global variable
- color and pon should be defined at the beginning od ParseData
- the closure pon looks strange to me. In javascript closures are usually written (function () {})(); the extra braces are for some obscure reason I can't really remember now.
- you assign the "closure" to an action of a button press.
- the return statement looks odd, should be just return  {....}

This is either some high level coding and I'm making an ass of myself for replying to this or something that is not written as should have been.

I find it strange that you provide the id as an argument to the pon function but not to the return function. Is id in pon even accessible from the return function? The message from the simulatroe would imply that no, it's not accessible.
OP | Post 3 made on Tuesday November 30, 2010 at 16:05
krissie
Lurking Member
Joined:
Posts:
November 2010
4
Here is the complete code
 
var httpLib = com.philips.HttpLibrary;
var actors;
 
for (var i = 0; i < MAX_LIGHTS; i++) 
{
  SetLineVisibility(i+1, false);
}
 
httpLib.getHTTP("[Link: 192.168.0.120], ParseData);
 
function SetLineVisibility(index, visible) 
{
  CF.widget("LBL_DESC_" + index).visible = visible;
  CF.widget("LBL_ICON_" + index).visible = visible;
  CF.widget("BTN_ON_" + index).visible = visible;
  CF.widget("BTN_OFF_" + index).visible = visible;
}
 
function ParseData(data) 
{
  var color;
  var i;
  function PowerOnUnit(unitid) {
    return function() {
      System.print("Power On " + unitid)
    };
  }
 
  
  actors = eval(data);
 
  for (i = 0; i < actors.length; i++) 
  {
    CF.widget("LBL_DESC_" + (i+1)).label = actors[i].description;
    actors[i].state > 0 ? color = 0x00ffff : color = 0xffffff;
    CF.widget("LBL_ICON_" + (i+1)).color = color;
    SetLineVisibility((i+1), true);
  
    CF.widget("BTN_ON_" + (i+1)).onPress = PowerOnUnit(actors[i].id);
  }
}


How would you write this code then ?

Thanks for replying !
Post 4 made on Tuesday November 30, 2010 at 17:13
Lyndel McGee
RC Moderator
Joined:
Posts:
August 2001
12,999
Your original error implied that actors was an array and element [i] of the array did not have a property/field named 'id'. It is caused by the reference to actors[i].id in this line:

CF.widget("BTN_ON_" + (i+1)).onPress = PowerOnUnit(actors[i].id);


Have you examined exactly what is being returned by the JSON script into the variable named data? Are you sure the content is correct?

I am also curious as to why you need the closure? The closure should work properly but I'm not sure why you need it.

Please see next post. Posted again vs editing!

Last edited by Lyndel McGee on November 30, 2010 20:51.
Lyndel McGee
Philips Pronto Addict/Beta Tester
Post 5 made on Tuesday November 30, 2010 at 20:49
Lyndel McGee
RC Moderator
Joined:
Posts:
August 2001
12,999
Ooops, I reviewed the code again and see that I missed the actual line that was reporting the error. Please try the following change:

function ParseData(data)
{
var color;
var i;
function PowerOnUnit(unitid) {

var tempId = unitid;
return function() {
System.print("Power On " + tempId);

};
}


actors = eval(data);

for (i = 0; i < actors.length; i++)
{
CF.widget("LBL_DESC_" + (i+1)).label = actors[i].description;
actors[i].state > 0 ? color = 0x00ffff : color = 0xffffff;
CF.widget("LBL_ICON_" + (i+1)).color = color;
SetLineVisibility((i+1), true);

CF.widget("BTN_ON_" + (i+1)).onPress = PowerOnUnit(actors[i].id);
}
}
Lyndel McGee
Philips Pronto Addict/Beta Tester
Post 6 made on Tuesday November 30, 2010 at 20:57
Lyndel McGee
RC Moderator
Joined:
Posts:
August 2001
12,999
And...

If you cannot get closure working, you can always store fields on the widget and reference them at time function is called using the 'this' keyword.

CF.widget("BTN_ON_" + (i+1)).myID = actors[i].id;

And inside your onPress function, you can do the following:

function pressHandler()
{
// this keyword points to actual widget inside onPress.
System.print(this.myID);
}

CF.widget("BTN_ON_" + (i+1)).onPress = pressHandler;
Lyndel McGee
Philips Pronto Addict/Beta Tester
Post 7 made on Wednesday December 1, 2010 at 04:02
BluPhenix
Long Time Member
Joined:
Posts:
December 2008
371
True, extending an existing object is usually the easier way of doing things. It's one of javascript's attributes I'm most happy about. Don't have a property you would need in an object, no problem just add it :).
Post 8 made on Thursday December 2, 2010 at 15:09
Lyndel McGee
RC Moderator
Joined:
Posts:
August 2001
12,999
So, Krissie, did you have a bug or change your code? Feedback is much appreciated...
Lyndel McGee
Philips Pronto Addict/Beta Tester
OP | Post 9 made on Friday December 3, 2010 at 13:27
krissie
Lurking Member
Joined:
Posts:
November 2010
4
Sorry for the late reply, I was a few days out ...

It works by setting the ID property on the button widget.
Great tip, thanks !

Last edited by Lyndel McGee (moderator) on December 4, 2010 10:32.
Post 10 made on Saturday December 4, 2010 at 10:34
Lyndel McGee
RC Moderator
Joined:
Posts:
August 2001
12,999
Note that if you set the ID, you should likely add an onRelease handler to clear the ID. This is especially true with Firm or Hard Keys.

function clearID()
{
delete this.myID;
}
CF.widget("BTN_ON_" + (i+1)).onRelease = clearID;
Lyndel McGee
Philips Pronto Addict/Beta Tester
OP | Post 11 made on Saturday December 4, 2010 at 12:42
krissie
Lurking Member
Joined:
Posts:
November 2010
4
thanks Lyndel, I'll keep that in mind !


Jump to


Protected Feature Before you can reply to a message...
You must first register for a Remote Central user account - it's fast and free! Or, if you already have an account, please login now.

Please read the following: Unsolicited commercial advertisements are absolutely not permitted on this forum. Other private buy & sell messages should be posted to our Marketplace. For information on how to advertise your service or product click here. Remote Central reserves the right to remove or modify any post that is deemed inappropriate.

Hosting Services by ipHouse