I have a Renderer:
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Metadata>
[Event(name="addToCart",type="event.ProductEvent")]
</fx:Metadata>
<fx:Script>
<![CDATA[
import events.ProductEvent;
import mx.collections.ArrayCollection;
protected function button1_clickHandler(event:MouseEvent):void
{
var eventObj:ProductEvent=new ProductEvent("addToCart",data.price,data.descript);
dispatchEvent(eventObj);
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:states>
<s:State name="normal"/>
<s:State name="hovered"/>
</s:states>
<s:BorderContainer >
<s:layout>
<s:VerticalLayout paddingBottom="10" paddingLeft="10" paddingRight="10" paddingTop="10"/>
</s:layout>
<s:Label text="{data.descript}"/>
<mx:Image source="{data.url}" width="50" height="50" width.hovered="100" height.hovered="100"/>
<s:Label text="{data.price}"/>
<s:Button includeIn="hovered" click="button1_clickHandler(event)" label="buy"/>
</s:BorderContainer>
</s:ItemRenderer>
and the custom event class:
package events
{
import flash.events.Event;
[Bindable]
public class ProductEvent extends Event
{
public var price:String;
public var descript:String;
public function ProductEvent(type:String,price:String, descript:String)
{
super(type);
this.price=price;
this.descript=descript;
}
override public function clone():Event
{
return new ProductEvent(type,price,descript);
}
}
}
but i cannot call that event in a container from the main application
<s:SkinnableDataContainer id="Sk" x="200" y="300" left="100" right="900" dataProvider="{imagesCollection}" itemRenderer="components.ImageRenderer" includeIn="normal" >
<s:layout>
<s:TileLayout/>
</s:layout>
</s:SkinnableDataContainer>
any ideas?
thanks
I want to make this:
<s:SkinnableDataContainer id="Sk" x="200" y="300" left="100" right="900" dataProvider="{imagesCollection}" itemRenderer="components.ImageRenderer" includeIn="normal" ***addToCart=something(event)*** >
Events are not called, so I'm not entirely sure what you want.
You can create an instance of an event class, like this:
var myProductEvent : ProductEvent = new ProductEvent("productEventTypeA", true, ...); // true is for enabling Bubbles, so that the event bubbles up to the listener.
You can dispatch that event from an itemRenderer the same way you would do so if you were using an event elsewhere:
dispatchEvent(myEvent);
Also on the item renderer, declare the event that is going to be dispatched:
[Event(name="productEventTypeA", type="local.events.ProductEvent")]
You can add an event listener on the List or DataGroup component implementing your item renderer so it runs your code after the event is dispatched:
myList.addEventListener("productEventTypeA", onProductEvent); // or a constant instead of "productEventTypeA"
or
myDataGroup.addEventListener("productEventTypeA", onProductEvent); // or a constant instead of "productEventTypeA"
And finally declare your listener function in the same file you added the event listener:
public function onProductEvent(e:ProductEvent):void
{
// do stuff
}
Note: In an itemRenderer, you often want to make your event bubble so that it can be listened to on the component which uses renderers--usually a list based class.
I hope this helps someone, you don't need to do all that...
It's very simple:
ItemRenderer:
protected function dispatchMyCustomEvent():void {
(owner as List).dispatchEvent(new CustomEvent);
}
if the parent isn't a list then just typecast it to what the parent is.
then in your component that has the list you can do the following:
protected function creationComplete():void {
myList.addEventListener(CustomEvent.TYPE, onMyCustomeEvent);
}
protected function onMyCustomEvent(event:MyCustomEvent):void {
// handle the event
}
It's hard to make out what you're trying to do from the question, because of the formatting, and it appears there's some text missing.
However. try making the event bubble, and add the event listener on the list which holds the itemRenderers.
Eg:
<mx:Canvas creationComplete="list1.addEventListener('addToCart',onAddToCart)">
<mx:List id="list1" itemRenderer="com.foo.YourItemRenderer" />
</mx:Canvas>
<!-- YourItemRenderer.mxml -->
<mx:Canvas>
<!-- Other item renderer stuff -->
<mx:Button click="dispatchEvent(new ProductEvent('addToCart'))" />
</mx:Canvas>
// ProductEvent.as
public class ProductEvent {
public function ProductEvent(type:String,bubbles:Boolean=true) {
super(type,bubbles);
// ... etc
}
}
Perhaps this is a little out of scope, but that sort of signaling with events is where MVC frameworks like Cairngorm shine. I usually think of them as AS event buses.
This is possible using the Event metadata tag: http://livedocs.adobe.com/flex/3/html/help.html?content=createevents_3.html
You'll have to sub-class SkinnableDataContainer and add the metadata tag:
[Event(name="addToCart", type="events.ProductEvent")]
public class MySkinnableDataContainer extends spark.components.SkinnableDataContainer
{
}
You can also do it in MXML:
<?xml version="1.0"?>
<!-- ../MySkinnableDataContainer.mxml -->
<s:SkinnableDataContainer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<mx:Script>
<![CDATA[
import events.ProductEvent;
]]>
</mx:Script>
<mx:Metadata>
[Event(name="addToCart", type="events.ProductEvent")]
</mx:Metadata>
</s:SkinnableDataContainer>
Then use this new class instead of the SkinnableDataContainer:
<MySkinnableDataContainer id="Sk" x="200" y="300" left="100" right="900" dataProvider="{imagesCollection}" itemRenderer="components.ImageRenderer" includeIn="normal" addToCart="something(event)" />
Note: depending on your events bubble property you may have to catch it and then re-forward it along inside of MySkinnableDataContainer.
Make the event bubble:
public function ProductEvent(type:String,price:String, descript:String)
{
super(type, true); // Add bubbles = true instead of default false
this.price=price;
this.descript=descript;
}
Then in your app:
<s:SkinnableDataContainer id="Sk" x="200" y="300" left="100" right="900" dataProvider="{imagesCollection}" itemRenderer="components.ImageRenderer" includeIn="normal" creationComplete="Sk.addEventListener('addToCart', myFunctionToHandle)">
Add an event listener on creation complete.
Related
I have 2 views.
This is the 1-st view.
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
title="MTA">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import adobe.utils.CustomActions;
import data.MTA_Item;
[Bindable]
public static var actions:ArrayCollection;
public var firstItem:MTA_Item;
public var secondItem:MTA_Item;
public var thirdItem:MTA_Item;
public function initItems():ArrayCollection
{
actions = new ArrayCollection();
firstItem = new MTA_Item(1,"Test","Test note");
secondItem = new MTA_Item(2,"DevCom","My First Notes");
thirdItem = new MTA_Item(3,"Auto" , "BMW");
actions.addItem(firstItem);
actions.addItem(secondItem);
actions.addItem(thirdItem);
return actions;
}
override public function set data(value:Object):void
{
if(actions == null)
initItems();
}
]]>
</fx:Script>
<s:VGroup>
<s:Label text="was" >
</s:Label>
</s:VGroup>
<s:List id="items" left="0" right="0" top="0" bottom="0" dataProvider="{actions}" change="navigator.pushView(FormDetails, items.selectedItem)">
<s:itemRenderer>
<fx:Component>
<s:IconItemRenderer label="ID:{data.ID}Name:{data.Name}" />
</fx:Component>
</s:itemRenderer>
</s:List>
</s:View>
2-nd view.
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import views.FlexMobileTestAppHomeView;
public function list_changeHandler(event:Event):void
{
var name:String = _namechange.text;
var notes:String = _note.text;
navigator.pushView(FlexMobileTestAppHomeView,data);
}
override public function set data(value:Object):void
{
}
]]>
</fx:Script>
<s:navigationContent>
<s:Button label="Back"
click="navigator.popToFirstView()"/>
</s:navigationContent>
<s:actionContent >
<s:Button label="save" click="list_changeHandler(event)" />
</s:actionContent>
<s:HGroup verticalAlign="middle" gap="12">
<s:VGroup>
<s:HGroup>
<s:Label text="Name:" />
<s:TextInput id="_namechange" text="{data.Name}">
</s:TextInput>
</s:HGroup>
<s:HGroup>
<s:Label text="Notes:"/>
<s:TextArea id="_note" text="{data.Notes}" />
</s:HGroup>
</s:VGroup>
</s:HGroup>
</s:View>
I need pass data to 2-nd.Then i must edit "name" , and "notes" and button save must return new data to 1-st view. How i can get "actions" from 1-st view and edit?
There are lots of ways to share data between two components. I wrote this blog post about the Flex facilities for sharing data between two Flex Components; however what I think you will be best suited with something more specific.
I'd look into these options:
Override the createReturnObject method in the second view. More information here. Be sure to read the comments for information about accessing the data in recent Flex versions.
Use a framework that supports Dependency Injection. RobotLegs and Swiz are two options I've used in the past. Basically, create a model object that contains a reference to a selectedItem and inject that into both views. Many would claim that this is the best way.
Store a reference to the selected object in a static variable; so that you can reference it in both views. This is a lot less of a learning curve than number 1.
Since you are already passing a reference to the component in the pushView method; are you sure the reference isn't automatically updated when you go back? Really both views are in essence using the same memory reference to get at the data. You may have to refresh the list for the list to pick up on the changes, though. Or I could be wrong on this one.
I am new to Flex and am having problems figuring out why this eventlistener always returns null for the event.data. I am trying to implement a simple yes/no prompt for data removal. I have included the skinnable container code and the calling mxml. The alertDB_close handler fires I know that but the event.data is empty. thanks for any suggestions
Main mxml:
protected function button1_clickHandler(event:MouseEvent):void
{
// Create an instance of MyAlertPopUp.
var alertDB:AlertMsgPurge = new AlertMsgPurge();
// Add an event handler for the close event to check for
// any returned data.
alertDB.addEventListener('close', alertDB_closeHandler);
alertDB.open(this, true);
}
private function alertDB_closeHandler(eventP:PopUpEvent):void {
// If commit is false, do data is returned.
rd.text = eventP.data as String;
//return;
/
}
AlertMsgPurge:
<?xml version="1.0" encoding="utf-8"?>
<s:SkinnablePopUpContainer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
// //
public function onClick(commit:Boolean):void {
close(true);
}
]]>
</fx:Script>
<s:TitleWindow title="" x="75" y="300">
<s:VGroup horizontalAlign="center" paddingTop="8" paddingBottom="8" paddingLeft="8" paddingRight="8" gap="5" width="100%">
<s:Label text="Warning!! all data will be deleted"/>
<s:Button label="Yes" click="close(true);"/>
<s:Button label="No" click="close(false);"/>
</s:VGroup>
</s:TitleWindow>
With that function modified:
private function alertDB_closeHandler(eventP:PopUpEvent):void {
trace("eventdata:"+eventP.commit);
}
You can see if the user clicked "yes" or "no" then you can do your processing.
Is it what your looking for?
I got a question about event dispatching and dispatching in flex.
My goal is to pass an email address captured in one component (Comp1) and be passed to another (Comp2). These two components are navigator content of a viewstack. The custom event dispatched the email correctly from Comp1 but somehow could not reach Comp2. The application (Main) looks like :
<fx:Script>
<![CDATA[
import events.LoginEventComplete;
protected function loginHandler(event:LoginEventComplete):void
{
myViewStack.selectedChild = idViewMain;
}
]]>
</fx:Script>
<s:Panel width="100%" height="100%">
<mx:ViewStack id="myViewStack" selectedIndex="0" width="100%" height="100%">
<views:Comp1 id="idViewLogin" login="loginHandler(event)"/>
<views:Comp2 id="idViewMain"/>
</mx:ViewStack>
</s:Panel>
The Comp1 looks like
<fx:Metadata>
[Event(name="login", type="events.LoginEventComplete")]
</fx:Metadata>
<fx:Script>
<![CDATA[
import events.LoginEventComplete;
protected function bnLogIn_clickHandler(event:MouseEvent):void{
var e:LoginEventComplete = new LoginEventComplete("login");
e.workemail = tiWorkEmail.text;
dispatchEvent(e);
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:layout>
<s:VerticalLayout verticalAlign="middle" horizontalAlign="center"/>
</s:layout>
<s:Panel width="400" height="500">
<s:Label text="Email" x="130" y="150"/>
<s:TextInput id="tiWorkEmail" top="140" left="180" right="60"/>
<s:Button
id="bnLogIn"
label="Log In"
top="220" left="180"
click="bnLogIn_clickHandler(event)"/>
</s:Panel>
The Comp2 looks like
<fx:Script>
<![CDATA[
import events.LoginEventComplete;
import valueObjects.Employee;
protected function init():void
{
this.addEventListener(LoginEventComplete.LOGIN, mainHandler);
}
private function mainHandler(event:LoginEventComplete):void{
tiWorkEmail.text = event.workemail;
}
]]>
</fx:Script>
<fx:Declarations>
</fx:Declarations>
<s:layout>
<s:VerticalLayout verticalAlign="middle" horizontalAlign="center"/>
</s:layout>
<s:Label id="idWorkEmail" text="Email"/>
<s:TextInput id="tiWorkEmail"/>
The custom event LoginEventComplete look like
package events
{
import flash.events.Event;
public class LoginEventComplete extends Event
{
public var workemail:String;
public static const LOGIN:String = "login";
public function LoginEventComplete(type:String)
{
super(type, true, false);
this.workemail = workemail;
}
override public function clone():Event
{
var newEvent:LoginEventComplete = new LoginEventComplete(type);
newEvent.workemail = workemail;
return newEvent;
}
}
}
Can someone help please? Many thanks!
Best David W
You're realizing one of the problems that any hierarchical view structure has to pass information. This problem can be solved in severals ways, but I feel that I should tell you that you might need to look into an application framework if your application is going to get large. One like Parsley or RobotLegs.
Now, onto a solution. You won't be able to use bubbling to go from one sibling component to another, since bubbling goes up the display list (child to parent and so on). You can either listen for the event on the common parent and then push the information into the other sibling, but that's adding a lot of logic on the parent container.
An easy fix would be to create a model (a class that just has public properties to store information) that is bindable on the parent and binded into both siblings. Then if one changes the information, the other can receive that same information (or use bindings).
For example:
<fx:Script>
<![CDATA[
import events.LoginEventComplete;
[Bindable] private var someData:SomeModel = new SomeModel();
protected function loginHandler(event:LoginEventComplete):void
{
myViewStack.selectedChild = idViewMain;
}
]]>
</fx:Script>
<s:Panel width="100%" height="100%">
<mx:ViewStack id="myViewStack" selectedIndex="0" width="100%" height="100%">
<views:Comp1 id="idViewLogin" login="loginHandler(event)" data="{someData}/>
<views:Comp2 id="idViewMain" data="{someData}/>
</mx:ViewStack>
</s:Panel>
I can tell you that dispatched events only move up the hierarchy chain. It sounds like, based on your first code segment, you are trying to get it to move sideways.
<mx:ViewStack id="myViewStack" selectedIndex="0" width="100%" height="100%">
<views:Comp1 id="idViewLogin" login="loginHandler(event)"/>
<views:Comp2 id="idViewMain"/>
</mx:ViewStack>
So, one solution is to have a listener in the main component for the event which then executes a public method in the comp2. It is probably the easiest route.
Another solution may be to store the value in a global object; which both components have references to.
I can't seem to get one of the most basic uses of events working in Flex 4. I've followed multiple tutorials and looked everywhere. From what I can tell, I'm doing everything right, so there must be some stupid mistake somewhere.
I have a main application file that contains a button. On clicking the button, it fires a custom event which I want my listener in my child component to catch. The event IS firing. The child component event listener is NOT catching that event. No clue why. The custom event is copy-pasted from Adobe's tutorial (minus the custom namespace and comments).
Main Application
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
applicationComplete="init()" xmlns:local="*">
<fx:Metadata>
[Event(name="enableChanged", type="EnableChangeEvent")]
</fx:Metadata>
<fx:Script>
<![CDATA[
import EnableChangeEvent;
import TestComponent;
private function doDispatchEvent(event:MouseEvent):void {
if(dispatchEvent(new EnableChangeEvent(EnableChangeEvent.ENABLE_CHANGED, true)))
{
statusLabel.text = "Event was dispatched";
}
}
public function init():void {
myButton.addEventListener(MouseEvent.CLICK, doDispatchEvent);
}
]]>
</fx:Script>
<s:Button x="95" y="83" label="Button" id="myButton" />
<s:Label x="230" y="83" text="" id="statusLabel" />
<local:TestComponent x="95" y="150" width="300" height="400" />
</s:WindowedApplication>
Child Component (Test)
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="100%" height="100%"
initialize="init();">
<fx:Script>
<![CDATA[
import EnableChangeEvent;
private function doFinalAction(event:EnableChangeEvent):void {
myLabel.text = "Custom Event Recieved";
}
private function init():void {
addEventListener(EnableChangeEvent.ENABLE_CHANGED, doFinalAction);
}
]]>
</fx:Script>
<s:Label width="300" height="50" text="Should change on click" id="myLabel" />
</s:Group>
Custom Event (from Adobe)
package {
import flash.events.Event;
public class EnableChangeEvent extends Event
{
public function EnableChangeEvent(type:String, isEnabled:Boolean=false) {
super(type);
this.isEnabled = isEnabled;
}
public static const ENABLE_CHANGED:String = "enableChanged";
public var isEnabled:Boolean;
override public function clone():Event {
return new EnableChangeEvent(type, isEnabled);
}
}
}
Timofei Davydik's answer it correct. Since the Application object dispatches the event, if you want your TestComponent object to catch it, you have to add a listener to a reference of the Application object from within your TestComponent. You can use the TestComponent object's inherited property "parentApplication" to get a reference to the Application object`.
Change the following code in TestComponent.mxml:
private function init():void
{
this.parentApplication.addEventListener(EnableChangeEvent.ENABLE_CHANGED, doFinalAction);
}// end function
[UPDATE]
Personally I feel like your going about using events the wrong way, so I made a similar flex application to demonstrate how to use events in flex.
Main.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:components="components.*"
xmlns:events="events.*"
applicationComplete="init()">
<fx:Script>
<![CDATA[
import events.EnableChangeEvent;
public function init():void
{
label1.text = "Application Complete!";
}// end function
private function onTestButtonEnableChanged(e:EnableChangeEvent):void
{
label2.text = "Enabled = " + e.isEnabled;
}// end function
]]>
</fx:Script>
<s:layout>
<s:VerticalLayout horizontalAlign="center" paddingTop="50" />
</s:layout>
<components:TestButton id="testButton" label="CLICK!" enableChanged="onTestButtonEnableChanged(event)" />
<s:Label id="label1"/>
<s:Label id="label2"/>
</s:WindowedApplication>
TestButton.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Button xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
click="onClick()">
<fx:Metadata>
[Event(name="enableChanged", type="events.EnableChangeEvent")]
</fx:Metadata>
<fx:Script>
<![CDATA[
import events.EnableChangeEvent
private var isEnabled:Boolean;
private function onClick():void
{
isEnabled = !isEnabled;
dispatchEvent(new EnableChangeEvent(EnableChangeEvent.ENABLE_CHANGED, isEnabled));
}// end function
]]>
</fx:Script>
</s:Button>
The main difference between the applications is that the Button object, in this case the TestButton object, dispatches the EnableChangeEvent event when clicked. While dispatching the event we can parse the boolean value for the _isEnabled property of TestButton to the event. Before, the value is inverted using the line isEnabled = !isEnabled. Now we can make use of handling the event using the mxml declaration of the TestButton object with the xml attribute enableChanged.
Also instead of following tutorials you might want to try a book like the one i'm reading. It's called "Adobe Flash Builder 4 and Flex 4 Bible" by David Gassner which you can get as a paperback book or a book for your kindle.
#Taurayi is correct, but to get you current code working with just one change, edit the init of Test Component to look like the following:
private function init():void
{
FlexGlobals.topLevelApplication.addEventListener(EnableChangeEvent.ENABLE_CHANGED, doFinalAction);
}
Your application object dispatches the custom event. Why do you expect your group to "catch" this event? It won't. Custom events have neither capturing nor bubbling phase. So, only listeners added to your application object will listen to this event.
I have a class defined like this:
public class Photo
{
public function Photo()
{
}
public var PhotoId:int;
public var Title :String;
public var Subtitle :String;
public var PhotoByteArray:ByteArray ;
public var ThumbnailByteArray:ByteArray;
public var ShowOnlyInFrontpageTop:Boolean;
public var ShowInFrontpageGroup:Boolean;
public var BackgroundColorGradientFrom:String;
public var BackgroundColorGradientTo:String;
public var IsActive :Boolean;
}
I 'm getting diverse objects of this type (Photo) from a WCF service (works fine!). These objects are stored in an ArrayCollection defined like this:
public static var GroupPhotos:ArrayCollection = new ArrayCollection();
I want to show up these photos using a s:List component, like this:
<s:List height="110" id="GroupPhotos" itemRenderer="MyGroupPhotoRenderer">
<s:layout >
<s:HorizontalLayout requestedColumnCount="3" />
</s:layout>
</s:List>
The item renderer is defined this way:
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
autoDrawBackground="true"
creationComplete="onItemrenderer_creationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.FlexEvent;
//when the item has been rendered and is ready to be shown the following method will be called
protected function onItemrenderer_creationCompleteHandler(event:FlexEvent):void
{
img.source = data.ThumbnailByteArray;
}
]]>
</fx:Script>
<s:Group id="PhotoGroup" width="297" height="110" >
<!--<s:Rect id="imgRectangle" alpha="0" width="95" height="65">
<s:stroke>
<s:LinearGradientStroke weight="{GroupBoxBorderWeight}" scaleMode="none"/>
</s:stroke>
</s:Rect>-->
<mx:Image id="img"
width="{PhotoGroup.width}" height="{PhotoGroup.height}"
/>
<s:Label id="title"
fontSize="20"
text="{data.Title}"/>
</s:Group>
</s:ItemRenderer>
The s:Label component shows up correctly whereas the mx:Image component shows up always the same image (don't know if this is the first Image or the last in the array).
What am i missing?
Thanks in advance
Ahhm!!Turns out that this my error! Above i stated that the service is running fine: guess what...it didn't! Fixing the service made the images show up correctly!
Creation complete is only called the first time your renderer is created. Since Flex reuses renderers that means it will only get called the first time. Instead of using creationComplete, override the set data method of your renderer. Unfortunately, s:ItemRenderer doesn't have a set data method, so I'd use a mx:HBox component instead.
Here's a quick example to get you started:
<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
override public function set data(value:Object):void
{
super.data = value;
theLabel.text = value["Title"].toString();
theImage.source = data.ThumbnailByteArray;
validateDisplayList();
}
]]>
</fx:Script>
<mx:Label id="theLabel" />
<mx:Image id="theImage" />
</mx:HBox>