Binding warnings when using Object in a List dataProvider
If you have built a custom item renderer for a DataGroup or List you may have come across warnings in your Flash Builder console output similar to this:
warning: unable to bind to property 'firstName' on class 'Object' (class is not an IEventDispatcher)
This kind of warning typically happens when you are trying to bind to an object or property that isn’t defined as Bindable. I’ve seen this issue come up often when working with dataProviders that use <fx:Object />. For example, when running this application:
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"> <s:List> <s:dataProvider> <s:ArrayList> <fx:Object firstName="Steve" lastName="Yzerman" /> <fx:Object firstName="Joe" lastName="Sakic" /> </s:ArrayList> </s:dataProvider> <s:itemRenderer> <fx:Component> <s:ItemRenderer> <s:HGroup> <s:Label text="{data.firstName}" /> <s:Label text="{data.lastName}" /> </s:HGroup> </s:ItemRenderer> </fx:Component> </s:itemRenderer> </s:List> </s:Application>
The Flash Builder console outputs:
warning: unable to bind to property 'firstName' on class 'Object' (class is not an IEventDispatcher) warning: unable to bind to property 'lastName' on class 'Object' (class is not an IEventDispatcher) warning: unable to bind to property 'firstName' on class 'Object' (class is not an IEventDispatcher) warning: unable to bind to property 'lastName' on class 'Object' (class is not an IEventDispatcher) warning: unable to bind to property 'firstName' on class 'Object' (class is not an IEventDispatcher) warning: unable to bind to property 'lastName' on class 'Object' (class is not an IEventDispatcher)
The issue is this custom inline renderer uses the { } binding syntax to bind to the value of data.firstName and data.lastName, but since the properties aren’t defined as bindable, changes to the data won’t get updated in the renderer (hence the warning).
There are two ways of changing your application to avoid these warnings.
1. Change your item renderer
Instead of binding the Label’s text property to the data you can override the set data method on the item renderer and update the Labels from there:
<s:ItemRenderer> <fx:Script> <![CDATA[ override public function set data(value:Object):void { txtFirstName.text = value.firstName; txtLastName.text = value.lastName; } ]]> </fx:Script> <s:HGroup> <s:Label id="txtFirstName" /> <s:Label id="txtLastName" /> </s:HGroup> </s:ItemRenderer>
If you aren’t comfortable overriding the set data method you might find it easier to listen for the dataChange event, for example:
<s:ItemRenderer dataChange="updateRenderer()"> <fx:Script> <![CDATA[ public function updateRenderer():void { txtFirstName.text = data.firstName; txtLastName.text = data.lastName; } ]]> </fx:Script> <s:HGroup> <s:Label id="txtFirstName" /> <s:Label id="txtLastName" /> </s:HGroup> </s:ItemRenderer>
Note: You should never key off of the creationComplete event in a spark item renderer unless you are fully aware of the consequences of item renderer recycling. Listening for the dataChange event is recommended.
2. Change the objects in your dataProvider
If you would like to take full advantage of the Binding syntax in your renderer then the objects in your dataProvider must be bindable. You can do this by creating a custom data type and defining some bindable properties on it. For example create a file called HockeyPlayer.as:
package { public class HockeyPlayer extends Object { [Bindable] public var firstName:String; [Bindable] public var lastName:String; } }
And then using this data structure in the dataProvider:
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:local="*"> <s:List> <s:dataProvider> <s:ArrayList> <local:HockeyPlayer firstName="Joe" lastName="Sakic" /> <local:HockeyPlayer firstName="Steve" lastName="Yzerman" /> </s:ArrayList> </s:dataProvider> <s:itemRenderer> <fx:Component> <s:ItemRenderer> <s:HGroup> <s:Label id="txtFirstName" text="{data.firstName}" /> <s:Label id="txtLastName" text="{data.lastName}" /> </s:HGroup> </s:ItemRenderer> </fx:Component> </s:itemRenderer> </s:List> </s:Application>
Note: This sample requires Flex SDK 4.0.0.11419 or higher. You can get the latest SDK builds from opensource.adobe.com.
Ah! Thanks for yer post. I have been looking for a solution on and off for months now, aye(:P).
I was having this ‘problem’ also, but solutions you suggest didn’t work for me. Here’s what I came up with:
PS. by the way, any idea how to validate my TextInput in this case?
@sasxa – Looks like WordPress swallowed up your code. If you want you can send me your code and I’ll take a look – steve at flexponential dot com
I found using an ObjectProxy as described here works well:
http://www.designovermatter.com/post.cfm/warning-unable-to-bind-to-property-somevar-on-object-object-class-is-not-an-ieventdispatcher
I found this easier than overriding the setter.
@johans – Thanks for the link, I had not thought of that approach before.
But this might not work as you would expect in spark. In general a spark ItemRenderer should never have logic waiting on the creationComplete event. This is because of item renderer recycling. If you do use the ObjectProxy approach you will still need to override the data setter (or handle the dataChange event) rather than having that logic in creationComplete.
I’ve added an extra code snippet to option 1 above to demonstrate keying off of the dataChange event instead of overriding set data since some find that more convenient.
Hi Steven,
I think avoiding using an ObjectProxy is the way to go – I can verify that things don’t work too well when you use that technique in Spark. I had thought the fact that I was using an ArrayCollection as the dataProvider on my list meant that I wouldn’t need to over-ride the setter, but I forgot about the data object – it’s just generic. Thanks.
The ‘updateRenderer()’ option worked for me.
Thank you.
Good work, well done.
Thanks for this, updateRenderer() works fine for me too
updateRenderer() is a good clean option, worked for me. Thanks