I stumbled on this simple and interesting bug with the List component in Flex: Adding an item with a label of "toString" to a List component will break the List, and take down much of your application with it. Just add the following to a new or existing mxml app (tested in Flex 2.0.1):
<mx:List dataProvider="['toString']"/>
I find this bug interesting because despite thinking it over last night (when I should have been sleeping), I still can't think of a good reason for why it occurs. The obvious culprit is the correlation between the string value, and List calling toString to get the label, and this somehow causes a conflict. I can't think of a scenario where this would cause an issue though - calling toString on a string will merely return the string value, regardless of what that value is. I even tested (amongst other things) calling toString on a "toString" String (wow, convoluted) to ensure this wasn't a deeper player level bug.
I haven't had time to track down the cause in the framework yet, but I plan to soon. It's bugging me, because I can't see why there would be any correlation between this specific value of the label, and the rendering of the list item. I also have a programmer's natural aversion to edge cases (what if my user adds an item named "toString", and my whole app blows up?).
Hopefully there will be more, in-depth blog entries to come in the not too distant future. There's been a lot of interesting stuff going on here at gskinner.com, including our work developing the v3 components set, continued work on our computer vision software, and our expansion into doing Flex work, which I'd love to blog about. Alas, my time is very short at the moment, between work, conferences, traveling, and building a new house (originally designed in Flash, though that's a story for another entry).
Comments (9)
could it be something in the List component using a custom toString method? I use these often in AS2 classes to return a static var that holds my class name. I have noticed AS3 acts differently with a trace(this); inside of a AS3 class by returning the class name.
static var className:String = "Main";
Posted by: jason vancleave at February 16, 2007 03:47 PMfunction toString():String
{
return className;
}
URL: http://jasonvancleave.com
I've seen the list components blow up too. The list component is interesting because the only items that are in the display list of the list are items that are currently being displayed....so when this starts going awry it can lead to really ugly results. I thought that we'd attributed our mishap to complex item renderers, but after this post, I'm goign to go back and look for toString()...
Posted by: Eric Cancil at February 16, 2007 06:11 PMThanks,
Eric
URL: http://blog.3r1c.net
It is a bug in the ListBase class and the drawItem method. It shows up when you have a data provider with a string value identical to one of the String method names.
That far I have come the last 10 minutes. I have to go now but I'll try to narrow it down some more later this weekend.
Cheers,
Posted by: Erwin Verdonk at February 17, 2007 01:32 AMErwin
URL:
*** Found the bug and the solution ***
Package: mx.controls.listClasses
Class: ListBase
Linenr: 3788
Original code:
o = selectionIndicators[rowData.uid];
Fixed code:
o = selectionIndicators[rowData.uid] as Sprite;
I have reported this bug to Adobe. Lets hope they will fix it soon. For now you can extend the subclass you are using of ListBase and override the drawItem() method and adjust the code yourself.
Cheers,
Posted by: Erwin Verdonk at February 17, 2007 03:02 AMErwin
URL:
Latest update:
It will give this error when a method name of the class Object (not String) is being used as string value. Reason for this is because "selectionIndicators" is an Object and when you do selectionIndicators["toString"] it will retrieve the method within the Object instance that is called "toString". This means that Object[value] will first seek for a method before it seeks for a variable with that name.
To be honest I have no idea why it does work when I cast that value to a Sprite. Somehow it appears to leave the methods alone when its being casted.
Posted by: Erwin Verdonk at February 17, 2007 03:48 AMURL:
Latest update:
I was wrong, sorry guys! Here is my latest findings
*** Found the bug and the solution ***
Package: mx.controls.listClasses
Class: ListBase
Method: drawItem()
Linenr: 3768
Original code:
if (!selectionIndicators[rowData.uid])
Fixed code:
if (!selectionIndicators[rowData.uid] || selectionIndicators[rowData.uid] is Function)
The original code only checked whether or not the variable already exists in the Object "selectionIndicators". Because Object always has function like "valueOf" and "toString" it will return a true for these values and starts working with the functions, which of course if not right. To solve this I added " || selectionIndicators[rowData.uid] is Function" to the IF statement so it will also check whether or not it is a function in the Object. When it is a function it will overwrite the function with the variable given by the data provider and work with that instead of the function.
This appears to work but it is risky since Object methods will become unavailable when you overwrite them. The real bug in fact that Adobe has made the mistake by using user input values as variable names in the Object. To solve this I probably have to write lots and lots of code in the ListBase class. For now this seems to be the solution since the "selectionIndicators" Object doesnt seem to make use of the Object methods.
I have reported this bug to Adobe. Lets hope they will fix it soon. For now you can extend the subclass you are using of ListBase and override the drawItem() method and adjust the code yourself.
Cheers,
Posted by: Erwin Verdonk at February 17, 2007 05:33 AMErwin
URL:
Another workaround would be to declare Objects in the dataprovider than strings (i guess thats a better practice). Here are some examples...
OR
import mx.collections.ArrayCollection;
[Bindable]private var myDP:ArrayCollection;
private function setDP():void{
myDP = new ArrayCollection([{methodLabel:"toString"},{methodLabel:"validateNow"},{methodLabel:"validateProperties"}, {methodLabel:"stylesInitialized"}]);
}
]]>
Posted by: Raghunath Rao at February 19, 2007 11:52 PMURL: http://raghunathraoflexing.blogspot.com/
Some problem in pushing code here. I'll mail it to you, drop me a mail.
Posted by: Raghunath Rao at February 19, 2007 11:53 PMURL: http://raghunathraoflexing.blogspot.com/
Thanks Raghu! I got your email. Check your inbox, there should be a mail there.
Posted by: Erwin Verdonk at February 20, 2007 12:09 PMURL: