I have an object in flex - which i want to appear upon a button clicked, disappear after 10 seconds or if the object is closed, and reappear if that same button pressed.
i've tried something like this:
public class my_obj
{
private var _myTimer: Timer;
public function my_obj()
{
_myTimer = new Timer(10000);
}
private function init(): void
{
_myTimer.addEventListener(TimerEvent.TIMER, onTimeout);
_myTimer.start();
}
private function onTimerTimeOut(event: TimerEvent): void
{
dispatchEvent(new Event(CLOSE_EVENT));
}
}
what am i missing?
Thanks!
Working fine. Here's the working code sample:
<?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">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:Panel width="100%" height="400" creationComplete="my_obj()">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
private var _myTimer: Timer;
public function my_obj():void
{
_myTimer = new Timer(10000);
}
private function init(): void
{
toggleBtn.visible = true;
_myTimer.addEventListener(TimerEvent.TIMER, onTimeout);
_myTimer.start();
}
private function onTimeout(event: TimerEvent): void
{
toggleBtn.visible = false;
//dispatchEvent(new Event(CLOSE_EVENT));
}
private function hideIt(): void
{
toggleBtn.visible = false;
}
]]>
</fx:Script>
<s:Button label="Some Button" click="init()"/>
<s:Button id="toggleBtn" label="Appeared on 'Some Button' click. Click to close it." click="hideIt()" visible="false"/>
</s:Panel>
</s:WindowedApplication>
Related
I have a datagrid with 2 columns. I need to access the item renderer of the second column whenever column-1 value changes. i.e if value of column 1 is A- need to display text field in column2 and if value is B, i need to show dropdown.
Col1----------Col2
A ---------- DropDown
B ---------- TextBox
A ---------- DropDown
Any Solutions???
public class ItemRendererfroDropTest extends GridItemRenderer
{
private var dropdown:DropDownList;
public function ItemRendererfroDropTest()
{
super();
dropdown=new DropDownList();
dropdown.dataProvider=new ArrayCollection(new Array("ABC","PQR"));
this.addElement(dropdown);
dropdown.addEventListener(FlexEvent.VALUE_COMMIT,dataChanged);
}
private function dataChanged(event:FlexEvent):void
{
owner.dispatchEvent(new CustomEvent(CustomEvent.DATA_CHANGED,true));
}
}
public class ItemRenderlabel extends GridItemRenderer
{
public var wlabel:Label=new Label();
public var checkbox:CheckBox=new CheckBox();
public function ItemRenderlabel()
{
super();
this.addEventListener(CustomEvent.DATA_CHANGED,mappingChanged,true);
this.addElement(wlabel);
}
private function mappingChanged(e:CustomEvent):void
{
Alert.show("asfAS");
}
}
You can get some idea from below code: - Event you can do it only for particular item by using dpHierarchy.itemUpdated() by updating individual row.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
creationComplete="init()">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.events.FlexEvent;
[Bindable]
private var dpHierarchy:ArrayCollection= new ArrayCollection([
{name:"A", region: "Arizona"},
{name:"B", region: "Arizona"},
{name:"C", region: "California"},
{name:"D", region: "California"}
]);
private function init():void
{
this.addEventListener(FlexEvent.DATA_CHANGE, changeDataHandler);
}
private function changeDataHandler(event:FlexEvent):void
{
dpHierarchy.refresh();
}
]]>
</fx:Script>
<mx:AdvancedDataGrid id="myADG"
width="100%" height="100%"
variableRowHeight="true" dataProvider="{dpHierarchy}">
<mx:columns>
<mx:AdvancedDataGridColumn dataField="name" headerText="Name" itemRenderer="AddComboboxADG"/>
<mx:AdvancedDataGridColumn dataField="region" headerText="Region" itemRenderer="SelectedCustomComponent"/>
</mx:columns>
</mx:AdvancedDataGrid>
</s:Application>
//AddComboboxADG custom item renderer
<?xml version="1.0" encoding="utf-8"?>
<s:MXAdvancedDataGridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
focusEnabled="true">
<fx:Script>
<![CDATA[
import mx.controls.AdvancedDataGrid;
import mx.controls.advancedDataGridClasses.AdvancedDataGridColumn;
import mx.controls.advancedDataGridClasses.AdvancedDataGridHeaderRenderer;
import mx.controls.advancedDataGridClasses.AdvancedDataGridListData;
import mx.events.AdvancedDataGridEvent;
import mx.events.DataGridEvent;
import mx.events.FlexEvent;
import mx.events.ItemClickEvent;
import spark.components.supportClasses.ItemRenderer;
import spark.events.IndexChangeEvent;
protected function comboBoxID_changeHandler(event:IndexChangeEvent):void
{
data.name = comboBoxID.selectedItem;
dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE, true));
}
override public function set data(value:Object):void
{
super.data = value;
if(data.name == "A")
{
comboBoxID.selectedIndex = 0;
}else if(data.name == "B")
{
comboBoxID.selectedIndex = 1;
}else if(data.name == "C")
{
comboBoxID.selectedIndex = 2;
}else
{
comboBoxID.selectedIndex = 3;
}
}
]]>
</fx:Script>
<s:DropDownList id="comboBoxID" change="comboBoxID_changeHandler(event)">
<s:ArrayCollection>
<fx:String>A</fx:String>
<fx:String>B</fx:String>
<fx:String>C</fx:String>
<fx:String>D</fx:String>
</s:ArrayCollection>
</s:DropDownList>
</s:MXAdvancedDataGridItemRenderer>
//SelectedCustomComponent custom item renderer
<?xml version="1.0" encoding="utf-8"?>
<s:MXAdvancedDataGridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
focusEnabled="true">
<fx:Script>
<![CDATA[
override public function set data(value:Object):void
{
super.data = value;
customFirstDropDown.visible = customTextInput.visible = customSecondDropDown.visible = lblData.visible = false;
if(data.name == "A")
{
customFirstDropDown.visible = true;
}else if(data.name == "B")
{
customTextInput.visible = true;
}else if(data.name == "C")
{
customSecondDropDown.visible = true;
}else
{
lblData.visible = true;
}
}
]]>
</fx:Script>
<s:DropDownList id="customFirstDropDown" visible="false" selectedIndex="0">
<s:ArrayCollection>
<fx:String>First</fx:String>
<fx:String>Second</fx:String>
<fx:String>Third</fx:String>
</s:ArrayCollection>
</s:DropDownList>
<s:TextInput id="customTextInput" visible="false" text="Selected"/>
<s:DropDownList id="customSecondDropDown" visible="false" selectedIndex="0">
<s:ArrayCollection>
<fx:String>1</fx:String>
<fx:String>2</fx:String>
<fx:String>3</fx:String>
</s:ArrayCollection>
</s:DropDownList>
<s:Label id="lblData" visible="false" text="Selected"/>
</s:MXAdvancedDataGridItemRenderer>
Create Item renderer using ViewStack with views as required, and override data function as normally done for item renderer, to set active child of container base of field, If you wants to set Active child on fly see this post
Hopes that helps
I have a custom Flex 4.5 component (to be used in a List) -
Game.mxml (represents a clickable playing table in a card game):
<?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"
xmlns:comps="*"
width="160" height="160"
autoDrawBackground="false"
creationComplete="init(event)">
<fx:Metadata>
[Event(name="pref_event", type="PrefEvent")]
</fx:Metadata>
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
private var _data:XML;
[Bindable("dataChange")]
public override function get data():Object {
return _data;
}
public override function set data(value:Object):void {
_data = value as XML;
if (null == _data)
return;
gameid = _data.#id;
for (var i:uint = 0; i < 3; i++) {
this['_user' + i].data = _data.elements('user')[i];
}
dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
}
public function init(event:FlexEvent):void {
_rect.filters = Util.SHADOW;
addEventListener(MouseEvent.CLICK, handleClick);
}
private function handleClick(event:MouseEvent):void {
trace("Clicked: " + gameid);
dispatchEvent(new PrefEvent(PrefEvent.GAME_CLICKED, gameid, true));
}
public function set gameid(str:String):void {
_gameid.text = '#' + str;
}
public function get gameid():String {
return _gameid.text.substring(1);
}
]]>
</fx:Script>
<s:Rect id="_rect" x="20" y="20" width="120" height="120" radiusX="16" radiusY="16">
<s:stroke>
<s:SolidColorStroke color="#4F69B5" weight="4"/>
</s:stroke>
<s:fill>
<s:SolidColor color="#CCDDEE" />
</s:fill>
</s:Rect>
<s:Label id="_gameid" x="0" y="75" width="{width}" fontSize="16" textAlign="center" color="#FFFFFF" />
<comps:User id="_user0" x="56" y="4" scaleX=".3" scaleY=".3" interactive="false" visible="false" />
<comps:User id="_user1" x="108" y="60" scaleX=".3" scaleY=".3" interactive="false" visible="false" />
<comps:User id="_user2" x="4" y="60" scaleX=".3" scaleY=".3" interactive="false" visible="false" />
</s:ItemRenderer>
and I'm trying to dispatch a custom event from it - PrefEvent.as:
package {
import flash.events.Event;
public class PrefEvent extends Event {
public var str:String;
public static const GAME_CLICKED:String = 'game_clicked';
public static const CARD_CLICKED:String = 'card_clicked';
public static const CARD_PLAYED:String = 'card_played';
public function PrefEvent(type:String, n:String, bubbles:Boolean = false, cancelable:Boolean = false){
super(type, bubbles,cancelable);
str = n;
}
public override function clone():Event {
return new PrefEvent(type, str, bubbles, cancelable);
}
public override function toString():String {
return str;
}
}
}
And here is finally my test code - GameTest.mxml:
<?xml version="1.0" encoding="utf-8"?>
<s:Application
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:comps="*"
width="700" height="525"
creationComplete="init()">
<fx:Script>
<![CDATA[
public function init():void {
game.data = <game id="8946">
<user id="OK353118989212"/>
<user id="OK351923295875"/>
</game>;
}
private function gameClicked(event:PrefEvent):void {
trace("game clicked: " + event);
}
]]>
</fx:Script>
<comps:Game id="game" x="0" y="0" pref_event="gameClicked(event)" />
</s:Application>
But I never see the "game clicked: " trace. Does anybody please know why?
I'm probably missing something minor, because I can see the "Clicked: 8946" trace.
Problem:
In Game.mxml File has "pref_event" Event
[Event(name="pref_event", type="PrefEvent")]
but your dispatching PrefEvent.GAME_CLICKED ("game_clicked").
Solution:
You must dispatch the right event for this.
dispatchEvent( new PrefEvent("pref_event",gameid, true) );
[Event(name="pref_event", type="PrefEvent")] != new PrefEvent(PrefEvent.GAME_CLICKED, gameid, true)
The name of the events are not the same.
You should write this in your Game.mxml file :
<fx:Metadata>
[Event(name="game_clicked", type="PrefEvent")]
</fx:Metadata>
And this in your main file :
<comps:Game id="game" x="0" y="0" game_clicked="gameClicked(event)" />
See here for further informations...
Is there a direct way to get the item index of the data inside an itemRenderer? I need to display the item number against each item. I am currently doing a workaround and won't allow reuse of my itemRenderer component.
var index:int = model.dataColl.getItemIndex(data) + 1;
itemNo = index.toString();
This is what i am using now, it works, but the concepts of component reuse and data abstraction are compromised.
I am using Flex 3.
The first answer seems to be working, but slow. It takes O(n^2) time as it runs through dataProvider array to get item index each time.
We can access rowIndex from listData - it represents index of the current visible item. Vertical scroll position from parent List represents the amount of scrolled items:
<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" implements="mx.controls.listClasses.IDropInListItemRenderer">
<mx:Script>
<![CDATA[
import mx.controls.listClasses.BaseListData;
import mx.controls.listClasses.ListBase;
[Bindable] private var index:int = 0;
private var _listData:BaseListData;
public function get listData():BaseListData
{
return _listData;
}
public function set listData(value:BaseListData):void
{
_listData = value;
}
override public function set data(value:Object):void
{
super.data = value;
if (data && listData)
index = _listData.rowIndex + ListBase(_listData.owner).verticalScrollPosition;
else
index = 0;
}
]]>
</mx:Script>
<mx:Label text="{index}"/>
<mx:Label text="{data.toString()}"/>
</mx:HBox>
You can use labelFunction to solve your problem. For the simple test application:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application creationComplete="init()" layout="absolute" xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
private static const DATA_LENGTH:Number = 100;
[Bindable]
private var dp:ArrayCollection;
private function countFinction(item:Object):String
{
return (dp.getItemIndex(item) + 1).toString();
}
private function init():void
{
var dataArray:Array = [];
for (var i:int = 0; i < DATA_LENGTH; i++)
{
var item:Object = { firstName: "First" + (i + 1), lastName: "Last" + (i + 1) };
dataArray.push(item);
}
dp = new ArrayCollection(dataArray);
}
]]>
</mx:Script>
<mx:List dataProvider="{dp}" height="500" horizontalCenter="0" itemRenderer="TestRenderer"
labelFunction="countFinction" verticalCenter="0" width="500" />
</mx:Application>
You can use the following test renderer:
<?xml version="1.0" encoding="utf-8"?>
<mx:HBox implements="mx.controls.listClasses.IDropInListItemRenderer" xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.controls.listClasses.BaseListData;
private var _listData:BaseListData;
/**
* #inheritDoc
*/
public function get listData():BaseListData
{
return _listData;
}
[Bindable(event = "listDataChanged")]
/**
* #inheritDoc
*/
public function set listData(value:BaseListData):void
{
if (value == _listData)
return;
_listData = value;
dispatchEvent(new Event("listDataChanged"));
}
]]>
</mx:Script>
<mx:Label fontWeight="bold" text="{listData.label}" />
<mx:Label text="{data.firstName + ' ' + data.lastName}" />
</mx:HBox>
Item renderer has an item index property on it.
this.itemIndex
Sample:
<s:List>
<s:dataProvider>
<s:ArrayList>
<fx:String>Item 1</fx:String>
<fx:String>Item 2</fx:String>
<fx:String>Item 3</fx:String>
<fx:String>Item 4</fx:String>
<fx:String>Item 5</fx:String>
<fx:String>Item 6</fx:String>
</s:ArrayList>
</s:dataProvider>
<s:itemRenderer>
<fx:Component>
<s:ItemRenderer>
<s:HGroup>
<s:Label text="This index is: {this.itemIndex}" />
<s:Label text="{data}" />
</s:HGroup>
</s:ItemRenderer>
</fx:Component>
</s:itemRenderer>
</s:List>
I am using the following .as file as the component for an itemrenderer in a list. Basically each item is rendered in a TextInput and each TextInput has a remove button as you can see from the code. When clicking the remove button, I want to remove the selectedItem..so I am putting the function removeItem() in MainMxml.xml and calling it from the .as file.
However I am getting an error "Cannot access a method or property of a null object reference". Can you help me out with this error?
The .as file as follows:
package components {
import flash.events.Event;
import flash.events.MouseEvent;
import mx.events.FlexEvent;
import renderers.TextInputRenderer;
import spark.components.Button;
import spark.components.TextInput;
import spark.events.TextOperationEvent;
public class ClearableTextInput extends TextInput {
[SkinPart(required="true")]
public var clearButton:Button;
[Bindable]
public var mainMxml:MainMxml;
public function ClearableTextInput() {
super();
//watch for programmatic changes to text property
this.addEventListener(FlexEvent.VALUE_COMMIT, textChangedHandler, false, 0, true);
//watch for user changes (aka typing) to text property
this.addEventListener(TextOperationEvent.CHANGE, textChangedHandler, false, 0, true);
}
private function textChangedHandler(e:Event):void {
if (clearButton) {
clearButton.visible = (text.length > 0);
}
}
private function clearClick(e:MouseEvent):void {
mainMxml.removeItem();
}
override protected function partAdded(partName:String, instance:Object):void {
super.partAdded(partName, instance);
if (instance == clearButton) {
clearButton.addEventListener(MouseEvent.CLICK, clearClick);
clearButton.visible = (text != null && text.length > 0);
}
}
override protected function partRemoved(partName:String, instance:Object):void {
super.partRemoved(partName, instance);
if (instance == clearButton) {
clearButton.removeEventListener(MouseEvent.CLICK, clearClick);
}
}
}
}
And the ItemRenderer is as such:
<?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" xmlns:components="components.*" width="100%">
<s:layout>
<s:HorizontalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import mx.core.EdgeMetrics;
import mx.core.UIComponent;
import skins.ClearableTextInputSkin;
]]>
</fx:Script>
<components:ClearableTextInput id="clearTxt" text="{data.label}" skinClass="skins.ClearableTextInputSkin" />
</s:ItemRenderer>
I am also setting the clear button in the ClearableTextInputSkin which is shown below:
<?xml version="1.0" encoding="utf-8"?>
<s:SparkSkin
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
minWidth="100" minHeight="22"
alpha.disabled="0.5"
blendMode="normal">
<fx:Metadata>
[HostComponent("components.ClearableTextInput")]
</fx:Metadata>
<!-- states -->
<s:states>
<s:State name="normal"/>
<s:State name="disabled"/>
</s:states>
<!-- bg -->
<s:Rect id="border" left="0" right="0" top="0" bottom="0" radiusX="3">
<s:fill>
<s:SolidColor id="bgFill" color="#ffffff" />
</s:fill>
<s:stroke>
<s:SolidColorStroke id="borderStroke" color="#333333" weight="1" />
</s:stroke>
</s:Rect>
<!-- text -->
<s:RichEditableText id="textDisplay" left="4" right="24" top="1" bottom="0"
color="#333333"
verticalAlign="middle" />
<s:Button id="clearButton" right="4" verticalCenter="0" />
</s:SparkSkin>
Your help would be much appreciated.
Many thanks.
The answer can be very very long :)
Starting with your code the problem is in line:
mainMxml.removeItem();
Your mainMxml instance is null and that's why you have your NPE (null pointer exception).
But the code in general shows that you currently don't understand Flex, especially data binding. And of course have problems with app's architecture.
First, your line:
[Bindable]
public var mainMxml:MainMxml;
doesn't do anything.
Data binding is just a way to listen changes of variable annotated with [Bindable] metatag. [Bindable] is not a kind of dependency injection but completely opposite of it.
So nobody set the value of your mainMxml field. And to tell the true, it is not the right way to try to inject value there. Instead of that, you should use Observer design pattern and fire event from your component:
package events {
public class ClearableTextInputEvent extends Event {
public static const PERFORM_CLEAR:String = "performClear";
public function ClearableTextInputEvent(type:String) {
super(type);
}
}
}
So now the component:
package components {
import flash.events.Event;
import flash.events.MouseEvent;
import mx.events.FlexEvent;
import renderers.TextInputRenderer;
import spark.components.Button;
import spark.components.TextInput;
import spark.events.TextOperationEvent;
[Event(name="performClear", type="events.ClearableTextInputEvent")]
public class ClearableTextInput extends TextInput {
[SkinPart(required="true")]
public var clearButton:Button;
public function ClearableTextInput() {
super();
//watch for programmatic changes to text property
this.addEventListener(FlexEvent.VALUE_COMMIT, textChangedHandler, false, 0, true);
//watch for user changes (aka typing) to text property
this.addEventListener(TextOperationEvent.CHANGE, textChangedHandler, false, 0, true);
}
private function textChangedHandler(e:Event):void {
if (clearButton) {
clearButton.visible = (text.length > 0);
}
}
private function clearClick(e:MouseEvent):void {
dispatchEvent(new ClearableTextInputEvent(ClearableTextInputEvent.PERFORM_CLEAR));
}
override protected function partAdded(partName:String, instance:Object):void {
super.partAdded(partName, instance);
if (instance == clearButton) {
clearButton.addEventListener(MouseEvent.CLICK, clearClick);
clearButton.visible = (text != null && text.length > 0);
}
}
override protected function partRemoved(partName:String, instance:Object):void {
super.partRemoved(partName, instance);
if (instance == clearButton) {
clearButton.removeEventListener(MouseEvent.CLICK, clearClick);
}
}
}
}
Ok. Now our renderer. There we should use event bubbling to inform our list container (I suppose it is an instance of MainMxml) about need to remove row. We should create an event class for that.
NB. You can use the same event class but the problem is your ClearableTextInput component and item renderer have different responsibilities
and ClearableTextInput can be used again in some other renderers. It is good practice to create different events for the different layers of your application for low coupling:
package events {
public class RemoveRowEvent extends Event {
public static const REMOVE_CURRENT_ROW:String = "removeCurrentRow";
public function RemoveRowEvent(type:String) {
super(type, true);
}
}
}
Now your 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"
autoDrawBackground="true" xmlns:components="components.*" width="100%">
<s:layout>
<s:HorizontalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import mx.core.EdgeMetrics;
import mx.core.UIComponent;
import skins.ClearableTextInputSkin;
]]>
</fx:Script>
<components:ClearableTextInput id="clearTxt" text="{data.label}" skinClass="skins.ClearableTextInputSkin" performClear="dispatchEvent(new RemoveRowEvent(RemoveRowEvent.REMOVE_CURRENT_ROW))" />
</s:ItemRenderer>
And finally in your list's container (MainMxml instance I suppose):
…
addEventListener(RemoveRowEvent.REMOVE_CURRENT_ROW, onRowRemove);
…
private function onRowRemove(event:RemoveRowEvent):void {
removeItem();
event.stopImmediatePropagation();
}
I wrote this draft in the browser so please fix imports etc. by yourself :)
I need to be able to call a method from a component located under the main application in Flex 4. Can anyone tell me please how to do this without using FlexGlobals please?
Sample code is attached. Thanks in advance.
// TestApp.mxml (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"
creationComplete="initApp()">
<fx:Script>
<![CDATA[
import com.TestComp;
import mx.managers.PopUpManager;
public function myMethod():void
{
// do something
}
protected function initApp():void
{
var popUp:TestComp = new TestComp();
PopUpManager.addPopUp(popUp, this, true);
}
]]>
</fx:Script>
</s:WindowedApplication>
// TestComp.mxml (component)
<?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="400" height="300">
<fx:Script>
<![CDATA[
private function doSomething(event:MouseEvent):void
{
// call to myMethod() in TestApp.mxml
}
]]>
</fx:Script>
<s:Button click="doSomething(event)" label="Click Me"/>
</s:Group>
This is bad design. You should provide a callback function or an event listener.
// TestComp.mxml
<mx:Metadata>
[Event(name="doSomethingEvent", type="flash.events.Event")]
</mx:Metadata>
<mx:Script><![CDATA[
private function doSomething(event:MouseEvent):void
{
this.dispatchEvent(new Event("doSomethingEvent"));
}
]]></mx:Script>
// TestApp.mxml
protected function initApp():void
{
var popUp:TestComp = new TestComp();
popUp.addEventListener("doSomethingEvent", myMethod);
PopUpManager.addPopUp(popUp, this, true);
}
private function myMethod(event: Event): void
{
// do something
}
And this is a callback example:
// TestComp.mxml
public var doSomethingCallback: Function;
private function doSomething(event:MouseEvent):void
{
doSomethingCallback.call();
}
// TestApp.mxml
protected function initApp():void
{
var popUp:TestComp = new TestComp();
popUp.doSomethingCallback = myMethod;
PopUpManager.addPopUp(popUp, this, true);
}
private function myMethod(): void
{
// do something
}
Easiest option?
Take out the click handler from the button in TestComp.
In your main app, add a listener to TestComp (if it's a direct child of the main application) or itself (if TestComp is further down the display list) for MouseEvent.CLICK. In the handler, test to see if the event's target is the TestComp either through == if you've got a direct reference, or through "is" if not.
That's the least amount of effort from what you have just now, still relies on (bubbling) events, and is more "correct"
I do agree with splash that it's bad design, but the following should work
//in TestApp
protected function initApp():void
{
var popUp:TestComp = new TestComp(this);
PopUpManager.addPopUp(popUp, this, true);
}
//in TestComp
private var app:TestApp;
public function TestComp(app:TestApp)
{
this.app = app;
}
private function doSomething(event:MouseEvent):void
{
// call to myMethod() in TestApp.mxml
app.myMethod();
}
or you could do it this way
//in TestApp
protected function initApp():void
{
var popUp:TestComp = new TestComp(this);
popUp.addEventListener( 'test' , eventListener );
PopUpManager.addPopUp(popUp, this, true);
}
private function eventListener(event:Event):void
{
//in which case myMethod doesn't need to be public
myMethod();
}
//in TestComp
private function doSomething(event:MouseEvent):void
{
dispatchEvent( new Event('test') );
}