I'm new to flex, and using a small open-source UI library ReCoral. In my test, I use its Application class as the root of mxml, and which has a click handler.
<?xml version="1.0" encoding="utf-8"?>
<common:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:common="geb.common.*" width="500" height="500"
xmlns:controls="geb.controls.*"
xmlns:mx="library://ns.adobe.com/flex/mx"
click="hello()">
<fx:Script>
<![CDATA[
private function hello(): void {
trace("world");
}
]]>
</fx:Script>
<controls:Label text="Click Me" height="100" width="100" click="hello()" />
</common:Application>
You can see the code is quite simple.
But when I click the Label, or the Application, the hello() method seems never invoked. I tried to add a breakpoint on the trace("world") line in debug mode, it had never been triggered.
Since the author is quite busy, and I'm new to flex, I don't know how to debug this problem.
Is there any way to listen any click event, and log the information?
Is there any useful document I should read?
Try this. You need to add the event type
<?xml version="1.0" encoding="utf-8"?>
<common:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:common="geb.common.*" width="500" height="500"
xmlns:controls="geb.controls.*"
xmlns:mx="library://ns.adobe.com/flex/mx"
click="hello()">
<fx:Script>
<![CDATA[
private function hello(event:MouseEvent): void {
trace("world");
}
]]>
</fx:Script>
<controls:Label text="Click Me" height="100" width="100" click="hello(event)" />
</common:Application>
I found the reason, that Label in RedCoral set mouseEnabled to false in inited method:
override protected function init():void
{
super.init();
mouseEnabled = false;
mouseChildren = false;
}
See: https://github.com/xiaotie/RedCoral/blob/master/src/geb/controls/Label.as#L112
So we should enable it:
<controls:Label text="Click Me" height="100" width="100" click="hello()" mouseEnabled="true" />
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 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>
This is really bugging me, but I have a component where a Button is wrapped in BorderContainer. I'm passing a custom property to the component at run-time to change the label of the button but Flex is reporting the following error:
Cannot access a property or method of a null object reference
When the error occurs, Flex highlights the following code:
myButton.label = value;
Here's the app:
// MyApp.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:local="*">
<local:MyComp id="myButton" label="My Button"/>
</s:WindowedApplication>
// MyComp.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:BorderContainer 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="400" height="300">
<fx:Script>
<![CDATA[
private var _label:String;
public function get label():String
{
return _label;
}
public function set label(value:String):void
{
_label = value;
myButton.label = value;
}
]]>
</fx:Script>
<s:Button id="myButton" label="Test"/>
</s:BorderContainer>
Any help would be greatly appreciated. Thanks in advance.
The myButton Object is not already created if the setter function for the label property is called the first time. Assign the new label value to myButton.label in commitProperties().
You should read About creating advanced components (most notably "About the component instantiation life cycle") to understand why.
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.