Weird behavior of custom item renderer in Flex 4 - apache-flex

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>

Related

flex mobile. how to back data?

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.

How do I use data from the main window in a sub-window?

I've just started working on a photo viewer type desktop AIR app with Flex. From the main window I can launch sub-windows, but in these sub-windows I can't seem to access the data I collected in the main window.
How can I access this data?
Or, how can I send this data to the sub-window on creation? It doesn't need to be dynamically linked.
myMain.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"
width="260" height="200"
title="myMain">
<fx:Declarations>
</fx:Declarations>
<fx:Script>
<![CDATA[
public function openWin():void {
new myWindow().open();
}
public var myData:Array = new Array('The Eiffel Tower','Paris','John Doe');
]]>
</fx:Script>
<s:Button x="10" y="10" width="240" label="open a sub-window" click="openWin();"/>
</s:WindowedApplication>
myWindow.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Window name="myWindow"
title="myWindow"
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
width="640" height="360">
<mx:Script>
<![CDATA[
]]>
</mx:Script>
<mx:Label id="comment" x="10" y="10" text=""/>
<mx:Label id="location" x="10" y="30" text=""/>
<mx:Label id="author" x="10" y="50" text=""/>
</mx:Window>
I realize this might be a very easy question but I have searched the web, read and watched tutorials on random AIR subjects for a few days and couldn't find it. The risk of looking like a fool is worth it now, I want to get on with my first app!
You could add an attribute to your window class, and pass the data from the application.
With an attribute and a setter function :
myWindow.mxml :
<![CDATA[
private var _data : Array;
public function set data(data : Array) : void {
this._data = data;
}
]]>
main
<![CDATA[
public function openWin():void {
var w : myWindow = new myWindow();
w.data = myData;
w.open();
}
public var myData:Array = new Array('The Eiffel Tower',
'Paris','John Doe');
]]>
You could also do it by adding a constructor parameter to your window, but you will have to write your Window component in ActionScript.
(Also : you might want to use MyWindow for the name of your component instead of myWindow, but that's just conventionnal nitpicking).
Also, note that there is a singleton variable Application.application that is accessible to all classes in an Application ; however I don't know if this applies to a WindowedApplication, and either way it is not the recommended approach.

Yet another Flex custom events in components question

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.

call a custom event from an item renderer in flex 4

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.

Deleting XML nodes from within a flex repeater doesn't work?

I have the following repeater code:
<mx:Repeater id="chapterRepeater" dataProvider="{Library.Book.Chapter}">
<mx:FormItem label="Chapter" direction="horizontal">
<mx:TextInput width="100" text="{ chapterRepeater.currentItem.#Name}"
change="event.currentTarget.getRepeaterItem().#Name = event.target.text"/>
<mx:NumericStepper maximum="2000" minimum="0" value="{chapterRepeater.currentItem.#Value}"
change="event.currentTarget.getRepeaterItem().#Value = event.target.value"/>
<mx:Button label="x" width="20" click="delete event.currentTarget.getRepeaterItem()"/>
</mx:FormItem>
</mx:Repeater>
Acting on the following XML
<Library Name="TestLibrary1">
<Book Name="TestBook1">
<Chapter Name="TestChapter1" Words="530"/>
<Chapter Name="TestChapter2" Words="490"/>
<Chapter Name="TestChapter3" Words="1030"/>
</Book>
</Library>
This allows the user to edit the names and values of the Chapter objects. However, the "delete" operation doesn't work for some reason?
Can anyone advise me as to how to reference items within a repeater in order to delete them?
Hmmm... this one has taken me a while to at least get to some sort of solution for it. In your click event (and subsequently the change events on the text area and numericStepper) you access currentTarget. CurrentTarget will actually return a reference to the button itself. As it is a button and not a repeater getRepeaterItem() would not return anything. I'm actually surprised that calling getRepeatItem() hasn't caused an error to be thrown. Needless to say that i don't think they were updating the xml.
My solution externalises the FormItem into it's own component (as that way, when click is fired i can bubble the event from the FormItem. That way i always know what formItem the event has come from) and then removes the item via an xmlListCollection.
So i have a separate component called ChapterFormItem.mxml which contains
<?xml version="1.0" encoding="utf-8"?>
<mx:FormItem xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
private var _chapterData : XML;
[Bindable]
public function get chapterData() : XML
{
return _chapterData;
}
public function set chapterData(value : XML) : void
{
_chapterData = value;
}
private function clickHandler(event : MouseEvent) : void
{
dispatchEvent(new Event("deleteChapter"));
}
private function textInputChangeHandler(event : Event) : void
{
chapterData.#Name = textInput.text;
}
private function numericStepperChangeHandler(event : Event) : void
{
chapterData.#Value = numericStepper.value;
}
]]>
</mx:Script>
<mx:Metadata>
[Event(name="deleteChapter", type="flash.events.Event")]
</mx:Metadata>
<mx:TextInput id="textInput" width="100" text="{chapterData.#Name}" change="textInputChangeHandler(event)"/>
<mx:NumericStepper id="numericStepper" maximum="2000" minimum="0" value="{chapterData.#Value}" change="numericStepperChangeHandler(event)"/>
<mx:Button label="x" width="20" click="clickHandler(event)"/>
</mx:FormItem>
and in the main application xml (for this example) i have
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" xmlns:local="*">
<mx:Script>
<![CDATA[
import mx.collections.XMLListCollection;
import mx.collections.ArrayCollection;
[Bindable]
private var xml:XML = <Library Name="TestLibrary1">
<Book Name="TestBook1">
<Chapter Name="TestChapter1" Words="530"/>
<Chapter Name="TestChapter2" Words="490"/>
<Chapter Name="TestChapter3" Words="1030"/>
</Book>
</Library>;
private function itemDeleteHandler(event : Event) : void
{
var chapterItem : ChapterFormItem = event.currentTarget as ChapterFormItem;
var chapterData : XML = chapterItem.chapterData;
var xmlListCollection : XMLListCollection = new XMLListCollection(xml.Book.Chapter);
var chapterDataIndex : int = xmlListCollection.getItemIndex(chapterData);
xmlListCollection.removeItemAt(chapterDataIndex);
}
]]>
</mx:Script>
<mx:Form width="100%" height="100%">
<mx:Repeater id="chapterRepeater" dataProvider="{xml.Book.Chapter}">
<local:ChapterFormItem label="Chapter"
direction="horizontal"
chapterData="{chapterRepeater.currentItem}"
deleteChapter="itemDeleteHandler(event)" />
</mx:Repeater>
</mx:Form>
</mx:Application>

Resources