I've reached the point where I have got a dropdown in which is embedded a tree. Each node has got a checkbox.
The idea is to be able to navigate and tick the checkboxes without having the dropdown closing.
Can't make this dropdown to remain open after a checkbox has been clicked!
The event that closes the dropdown occurs when the xml is updated in PermissionTreeItemRendererV2.as > handleChkClick(evt) > this.itemXml.#checked = {"0" or "1"};
Any idea how to tweak the code to disable this annoying event?
sample_combobox.mxml:
<?xml version="1.0"?>
<mx:Application xmlns:local="local.*"
xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="loadXML()">
<mx:Script>
<![CDATA[
import mx.collections.XMLListCollection;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.mxml.HTTPService;
public var xmlService:HTTPService = new HTTPService();
[Bindable]
public var xmlResult:XML;
[Bindable]
public var xmlList:XMLList;
[Bindable]
public var xmlTeams:XMLListCollection;
public function loadXML():void
{
xmlService.url = "mlb.xml"
xmlService.resultFormat = "e4x";
xmlService.addEventListener(ResultEvent.RESULT, resultHandler);
xmlService.send();
}
public function resultHandler(event:ResultEvent):void
{
xmlResult = XML(event.result);
xmlList = xmlResult.league;
xmlTeams = new XMLListCollection(xmlList);
}
]]>
</mx:Script>
<local:TreeComboBox
width="300"
id="combo"
labelField="#label" dataProvider="{xmlTeams}" />
</mx:Application>
TreeCombobox.mxml:
<?xml version="1.0" encoding="utf-8"?>
<local:ComboBoxNoClose xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:local="local.*">
<mx:Script>
<![CDATA[
import mx.events.FlexEvent;
[Bindable]
private var _label:String;
[Bindable]
public var treeSelectedItem:Object;
public function updateLabel(event:*):void
{
_label = event.currentTarget.selectedItem[this.labelField];
treeSelectedItem = event.currentTarget.selectedItem;
}
override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
if(dropdown && _label != null){
text = "";//_label;
}
}
]]>
</mx:Script>
<local:dropdownFactory>
<mx:Component>
<mx:Tree change="outerDocument.updateLabel(event)" height="500"
width="500"
itemRenderer="local.PermissionsTreeItemRendererV2"
folderClosedIcon="{null}"
folderOpenIcon="{null}"
defaultLeafIcon="{null}" />
</mx:Component>
</local:dropdownFactory>
</local:ComboBoxNoClose>
PermissionTreeItemRendererV2.as
// ActionScript file
package local
{
import flash.events.Event;
import flash.events.MouseEvent;
import mx.collections.ArrayCollection;
import mx.collections.ArrayList;
import mx.collections.ListCollectionView;
import mx.controls.CheckBox;
import mx.controls.treeClasses.TreeItemRenderer;
import mx.controls.treeClasses.TreeListData;
public class PermissionsTreeItemRendererV2 extends TreeItemRenderer{
public var chk:CheckBox;
public var itemXml:XML;
public function PermissionsTreeItemRendererV2(){
super();
mouseEnabled = false;
}
override public function set data(value:Object):void{
if(value != null){
super.data = value;
this.itemXml = XML(value);
if(this.itemXml.#checked == "1"){
this.chk.selected = true;
}else{
this.chk.selected = false;
}
}
}
override protected function createChildren():void{
super.createChildren();
chk = new CheckBox();
chk.addEventListener(MouseEvent.CLICK, handleChkClick);
addChild(chk);
}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{
super.updateDisplayList(unscaledWidth,unscaledHeight);
if(super.data){
var tld:TreeListData = TreeListData(super.listData);
//In some cases you only want a checkbox to appear if an
//item is a leaf
//if so, then keep the following block uncommented,
//otherwise you can comment it out to display the checkbox
//for branch nodes
if(tld.hasChildren){
this.chk.visible = true;
}else{
//You HAVE to have the else case to set visible to true
//even though you'd think the default would be visible
//it's an issue with itemrenderers...
this.chk.visible = true;
}
if(chk.visible){
//if the checkbox is visible then
//reposition the controls to make room for checkbox
this.chk.x = super.label.x
super.label.x = this.chk.x + 17;
this.chk.y = super.label.y+8;
}
}
}
private function handleChkClick(evt:MouseEvent):void
{
if(this.chk.selected)
{
this.itemXml.#checked = "1";
}
else
{
this.itemXml.#checked = "0";
}
}
}
}
ComboboxNoClose.as:
package local
{
import flash.events.Event;
import flash.events.MouseEvent;
import mx.controls.CheckBox;
import mx.controls.ComboBox;
import mx.events.DropdownEvent;
import mx.events.ListEvent;
public class ComboBoxNoClose extends ComboBox
{
public function ComboBoxNoClose()
{
super();
}
public function onOpen(event:Event):void
{
event.stopImmediatePropagation();
}
public override function close(trigger:Event = null):void
{
if (trigger != null)
{
super.close();
}
}
}
}
mlb.xml that populates the tree:
<?xml version="1.0" encoding="utf-8"?>
<root>
<league label="American League">
<division label="West">
<team label="Los Angeles" />
<team label="Seattle" />
<team label="Oakland" />
<team label="Texas" />
</division>
<division label="Central">
<team label="Cleveland" />
<team label="Detroit" />
<team label="Minnesota" />
<team label="Chicago" />
<team label="Kansas City" />
</division>
<division label="East">
<team label="Boston" />
<team label="New York" />
<team label="Toronto" />
<team label="Baltimore" />
<team label="Tampa Bay" />
</division>
</league>
</root>
Default behavior of popup is that, when you click on dropdown it closes it self. You can solve this problem like this
<mx:PopUpButton id="popup" width="100%" label="{label}" close="popup_closeHandler(event)" open="popup_openHandler(event)" openAlways="true">
<mx:popUp>
<mx:VBox width="{popup.width*1.25}" mouseEnabled="false" verticalGap="1">
<mx:List id="listSelectAll" width="100%" rowCount="1" selectable="true" itemClick="listSelectAll_itemClickHandler(event)">
<mx:dataProvider>
<mx:Array>
<mx:Object id="selectAll" selected="" label="All"/>
</mx:Array>
</mx:dataProvider>
<mx:itemRenderer>
<mx:Component>
<mx:HBox width="100%" height="100%" mouseChildren="false">
<mx:CheckBox selected="{data.selected}" label="{data.label}" width="100%"/>
</mx:HBox>
</mx:Component>
</mx:itemRenderer>
</mx:List>
<mx:List id="listItems" width="100%" dataProvider="{_dataProvider}" itemClick="listItems_itemClickHandler(event)" variableRowHeight="true">
<mx:itemRenderer>
<mx:Component>
<!--
<mx:HBox width="100%" height="100%" mouseChildren="false" verticalAlign="middle">
<mx:CheckBox selected="{data[outerDocument.selectedField]}" label="{data[outerDocument.labelField]}" width="100%"/>
</mx:HBox>
-->
<mx:HBox width="100%" mouseChildren="false" verticalAlign="middle" horizontalAlign="left" paddingLeft="4">
<mx:Script>
<![CDATA[
override public function set data(value: Object) : void {
super.data = value;
if(data.iconCache == null || outerDocument.cacheIcon == false) {
imgIcon.source = data[outerDocument.iconField];
} else {
imgIcon.source = new Bitmap(data.iconCache);
}
}
protected function image_ioErrorHandler(event:IOErrorEvent):void {
imgIcon.visible = imgIcon.includeInLayout = false;
}
protected function imgIcon_completeHandler(event:Event):void {
imgIcon.visible = imgIcon.includeInLayout = true;
if(outerDocument.cacheIcon) {
var bitmapData:BitmapData = Bitmap(imgIcon.content).bitmapData;
//var bitmap:Bitmap = new Bitmap(bitmapData);
data.iconCache = bitmapData;
//imgIcon.removeEventListener(Event.COMPLETE, imgIcon_completeHandler);
}
}
]]>
</mx:Script>
<mx:CheckBox id="chkSelected" selected="{data[outerDocument.selectedField]}"/>
<mx:Image id="imgIcon" width="{outerDocument.iconWidth}" height="{outerDocument.iconHeight}" visible="{data[outerDocument.iconField]}" includeInLayout="{data[outerDocument.iconField]}" complete="imgIcon_completeHandler(event)" ioError="image_ioErrorHandler(event)"/>
<mx:Label id="lblText" text="{data[outerDocument.labelField]}"/>
</mx:HBox>
</mx:Component>
</mx:itemRenderer>
</mx:List>
</mx:VBox>
</mx:popUp>
</mx:PopUpButton>
or you can visit my post for a complete implementation. here
Related
I'm having a sizing issue with a canvases located inside an HBox. It seems "_graphic", "_border" and "_fill" canvases (in com.example.ThingRenderer.mxml) do not get measured at the same time as all the other measurements inside the renderer. However, this problem is only observed on the first pass-through. Refer to the images for a visual... 1st image shows the state of the app after it finished loading. 2nd image represents what the screen looks like after the Populate button is clicked. 3rd image shows what happens when the stepper is incremented. The question is how come the drawing in the 3rd image doesn't get rendered once the data is populated into the table?
RendererTest.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
creationComplete="handleCreationComplete(event)"
>
<mx:Script>
<![CDATA[
import com.example.Thing;
import mx.collections.ArrayCollection;
import mx.events.FlexEvent;
import mx.events.NumericStepperEvent;
private const _thingProvider:ArrayCollection = new ArrayCollection();
private var _thing1:Thing;
protected function handleCreationComplete(event:FlexEvent):void {
_thing1 = new Thing("thingy", 0xff0000, 0.3);
_stepper.value = _thing1.ratio;
}
protected function handlePopulateClick(event:MouseEvent):void {
_thingProvider.addItem(_thing1);
}
protected function handleStepperChange(event:NumericStepperEvent):void {
_thing1.ratio = event.value;
}
]]>
</mx:Script>
<mx:VBox>
<mx:Button label="Populate" click="handlePopulateClick(event)" />
<mx:NumericStepper id="_stepper" minimum="0" maximum="1" stepSize="0.01" change="handleStepperChange(event)" />
<mx:AdvancedDataGrid dataProvider="{_thingProvider}" variableRowHeight="true" width="100%" height="100%">
<mx:columns>
<mx:AdvancedDataGridColumn headerText="Name" dataField="name" />
<mx:AdvancedDataGridColumn headerText="Display"
width="150" sortable="false"
itemRenderer="com.example.ThingRenderer"
/>
</mx:columns>
</mx:AdvancedDataGrid>
</mx:VBox>
</mx:Application>
com.exampleThingRenderer.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas
xmlns:mx="http://www.adobe.com/2006/mxml"
width="100%"
horizontalScrollPolicy="off" verticalScrollPolicy="off"
>
<mx:Script>
<![CDATA[
import mx.binding.utils.ChangeWatcher;
private var _thing:Thing;
private var _ratioWatcher:ChangeWatcher;
private var _doClearContent:Boolean;
private var _doDrawBorder:Boolean;
private var _doUpdateFill:Boolean;
override public function set data(value:Object):void {
if(value && value is Thing) {
_thing = Thing(value);
if(_ratioWatcher) {
_ratioWatcher.unwatch();
}
_ratioWatcher = ChangeWatcher.watch(_thing, "ratio", handleRatioChanged);
_doClearContent = false;
_doDrawBorder = true;
_doUpdateFill = true;
_graphic.invalidateSize();
_border.invalidateSize();
}
else {
_doClearContent = true;
_doDrawBorder = false;
_doUpdateFill = false;
}
super.data = value;
}
private function handleRatioChanged(event:Event):void {
_doUpdateFill = true;
invalidateDisplayList();
}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
if(_doClearContent) {
_container.visible = false;
_container.includeInLayout = false;
_doClearContent = false;
}
super.updateDisplayList(unscaledWidth, unscaledHeight);
if(_doDrawBorder) {
trace("_thingContainer.width="+_container.width, "_thingGraphic.width="+_graphic.width, "_thingBorder.width="+_border.width);
_border.graphics.clear();
_border.graphics.moveTo(0, 0);
_border.graphics.lineStyle(1, _thing.color);
_border.graphics.lineTo(_border.width, 0);
_border.graphics.lineTo(_border.width, _border.height);
_border.graphics.lineTo(0, _border.height);
_border.graphics.lineTo(0, 0);
_doDrawBorder = false;
}
if(_doUpdateFill) {
_percentage.text = Math.round(_thing.ratio * 100.0) + "%";
_fill.graphics.clear();
_fill.graphics.beginFill(_thing.color);
_fill.graphics.drawRect(0, 0, _fill.width * _thing.ratio, _fill.height);
_doUpdateFill = false;
}
}
]]>
</mx:Script>
<mx:HBox id="_container" width="100%" paddingLeft="5" paddingTop="5" paddingRight="5" paddingBottom="5">
<mx:Label id="_percentage" width="45" />
<mx:Canvas id="_graphic" width="100%" height="15">
<mx:Canvas id="_border" x="0" y="0" width="100%" height="100%" />
<mx:Canvas id="_fill" x="0" y="0" width="100%" height="100%" />
</mx:Canvas>
</mx:HBox>
</mx:Canvas>
com.example.Thing.as
package com.example {
public class Thing {
[Bindable] public var name:String;
[Bindable] public var color:uint;
[Bindable] public var ratio:Number;
public function Thing(name:String, color:uint, ratio:Number) {
this.name = name;
this.color = color;
this.ratio = ratio;
}
}
}
All this happens because you can't use width and height properties in updateDisplayList, they are not updated yet. Make separate component (e.g. ThingProgressBar) and put drawing logick inside it, that will solve everything:
package
{
import mx.core.UIComponent;
public class ThingProgressBar extends UIComponent
{
private var _ratio:Number;
public function get ratio():Number
{
return _ratio;
}
public function set ratio(value:Number):void
{
_ratio = value;
invalidateDisplayList();
}
override protected function updateDisplayList(
unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
graphics.clear();
if (unscaledWidth > 0 && unscaledHeight > 0)
{
graphics.lineStyle(1, 0xFF0000);
graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
graphics.beginFill(0xFF0000);
graphics.drawRect(0, 0, unscaledWidth * ratio, unscaledHeight);
graphics.endFill();
}
}
}
}
So your renderer might look like this:
<mx:HBox
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
horizontalScrollPolicy="off" verticalScrollPolicy="off" xmlns:local="*"
>
<fx:Script>
<![CDATA[
[Bindable] private var _thing:Thing;
override public function set data(value:Object):void
{
_thing = value as Thing;
super.data = value;
}
]]>
</fx:Script>
<mx:HBox width="100%"
paddingLeft="5" paddingTop="5"
paddingRight="5" paddingBottom="5">
<mx:Label text="{_thing.name}" width="45" />
<local:ThingProgressBar width="100%" height="15"
ratio="{_thing.ratio}"/>
</mx:HBox>
</mx:HBox>
I removed watcher. Binding by watcher is considered a bad practice, use mxml binding or events instead.
I removed two Canvases with separated border and fill - they can be cobined together.
I used UIComponent instead of Canvas. Don't use containers unless you need layout, they are heavy.
I used HBox instead of Canvas in renderer because I like boxes more :) But you can't avoid using second container in renderer if you need custom styles since List overwrites renderer's stylesheet.
Many thanks to www.Flextras.com who has been helping me with this question the last couple of days, and I almost have it. I have a main.mxml, child.mxml and headermenu.mxml. I click a button on the headermenu that dispatches an event up to the main.mxml which then executes a method in child.mxml. I know this works because I put an AlertDialog in the function I'm calling inside of the child.mxml. The child.mxml contains a drawingArea object that has an erase(). When I call this directly from child.xml it executes, however if I put drawingArea.erase() inside of the function being called by child's parent (main.mxml) nothing happens.
Here is my code:
Telestrator.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:MobileApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" firstView="views.TelestratorHome" creationComplete="creationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import mx.effects.Fade;
import mx.events.ChildExistenceChangedEvent;
import mx.events.EffectEvent;
import mx.events.FlexEvent;
import mx.events.ResizeEvent;
import mx.managers.PopUpManager;
import qnx.dialog.AlertDialog;
import qnx.events.QNXApplicationEvent;
import qnx.system.QNXApplication;
import views.TelestratorHome;
private var headerTimer:Timer = new Timer(5000,1);
[Bindable] private var headerMenu:HeaderMenu;
[Bindable] private var headerMenuDisplayed:Boolean = false;
private var tele:TelestratorHome;
private var alert2:AlertDialog = new AlertDialog();
protected function creationCompleteHandler(event:FlexEvent):void
{
QNXApplication.qnxApplication.addEventListener(QNXApplicationEvent.SWIPE_DOWN, onApplicationSwipeDown);
headerMenu = new HeaderMenu();
headerMenu.addEventListener(MouseEvent.CLICK, onHeaderMenuClick);
this.tele = new TelestratorHome();
this.tele.width = 100;
this.tele.height = 100;
this.tele.x = 10;
this.tele.y = 10;
this.addChild( tele );
headerMenu.addEventListener('parentDoSomething', onHeaderBarToldMeTo);
headerTimer.addEventListener(TimerEvent.TIMER, onHeaderMenuTimerEvent);
}
protected function onApplicationSwipeDown(event:QNXApplicationEvent) : void
{
showHeaderMenuPopup();
}
private function showHeaderMenuPopup() : void
{
if (!headerMenuDisplayed)
{
headerMenu.x = 0;
headerMenu.y = 0;
PopUpManager.addPopUp(headerMenu,this, false);
headerPopupEffectIn.end();
headerPopupEffectIn.play();
headerMenuDisplayed = true;
}
headerTimer.reset();
headerTimer.start();
}
private function onHeaderMenuTimerEvent(event:TimerEvent) : void
{
hideHeaderMenuPopup();
headerTimer.stop();
}
private function onHeaderMenuClick(event:MouseEvent) : void
{
hideHeaderMenuPopup();
}
private function hideHeaderMenuPopup() : void
{
headerPopupEffectOut.end();
headerPopupEffectOut.play();
headerPopupEffectOut.addEventListener(EffectEvent.EFFECT_END, headerMenuHidden);
}
private function headerMenuHidden(event:EffectEvent) : void
{
PopUpManager.removePopUp(headerMenu);
headerPopupEffectIn.removeEventListener(EffectEvent.EFFECT_END, headerMenuHidden);
headerMenuDisplayed = false;
}
protected function onHeaderBarToldMeTo(event:Event):void{
tele.eraseCanvas(event);
}
]]>
</fx:Script>
<fx:Declarations>
<s:Parallel id="headerPopupEffectIn" target="{headerMenu}">
<s:Move duration="250" yFrom="-75" xTo="0" yTo="0" easer="{sineEaser}" />
</s:Parallel>
<s:Parallel id="headerPopupEffectOut" target="{headerMenu}">
<s:Move duration="250" yFrom="0" xTo="0" yTo="-75" easer="{sineEaser}" />
</s:Parallel>
<s:Sine id="sineEaser" easeInFraction="0.2" />
</fx:Declarations>
</s:MobileApplication>
TelestratorHome.mxml
------------------
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
actionBarVisible="true" creationComplete="init()" overlayControls="false"
tabBarVisible="true" title="Telestrator">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:actionContent>
<s:Button label="Erase" click="drawingArea.erase(event)"/>
<s:Button id="saveBtn" label="Save Image" click="save()" visible="false"/>
</s:actionContent>
<s:titleContent>
<s:Button label="Take Photo" click="takeSnapshot()"/>
</s:titleContent>
<s:Panel id="p" top="1" width="1024" height="600" backgroundAlpha="0.0" horizontalCenter="0">
<s:Panel id="imageViewer" top="-32" width="1024" height="600" backgroundAlpha="0.0" horizontalCenter="0"/>
<s:Panel id="preview" top="-32" width="1024" height="600" backgroundAlpha="0.0" horizontalCenter="0"/>
<DrawingArea xmlns="*" id="drawingArea" y="-32" width="100%" height="509"/>
</s:Panel>
<fx:Script>
<![CDATA[
import com.tinkerlog.WebCam;
import com.tinkerlog.util.Base64;
import flash.media.Camera;
import mx.core.UIComponent;
import mx.graphics.codec.JPEGEncoder;
import mx.graphics.codec.PNGEncoder;
import qnx.dialog.AlertDialog;
private var webCam:WebCam;
private var alert3:AlertDialog = new AlertDialog();
private function init():void {
webCam = new WebCam(1024, 600);
var ref:UIComponent = new UIComponent();
preview.removeAllElements();
preview.addElement(ref);
ref.addChild(webCam);
}
private function takeSnapshot():void {
imageViewer.visible = true;
preview.visible=false;
saveBtn.visible = true;
imageViewer.width = preview.width;
imageViewer.height = preview.height;
var uiComponent : UIComponent = new UIComponent();
uiComponent.width = webCam.width;
uiComponent.height = webCam.height;
var photoData:Bitmap = webCam.getSnapshot();
var photoBitmap:BitmapData = photoData.bitmapData;
uiComponent.addChild(photoData);
imageViewer.removeAllElements();
imageViewer.addElement(uiComponent);
}
private function deleteSnapshot():void {
imageViewer.removeAllElements();
}
public function save():void
{
var bd:BitmapData = new BitmapData(p.width, p.height);
bd.draw(this);
var ba:ByteArray = (new PNGEncoder()).encode(bd);
(new FileReference()).save(ba, "doodle.png");
}
public function eraseCanvas(event:Event):void{
drawingArea.erase(event);
}
]]>
</fx:Script>
</s:View>
HeaderMenu.mxml
--------------
<?xml version="1.0" encoding="utf-8"?>
<s:BorderContainer xmlns:fx="http://ns.adobe.com/mxml/2009" borderVisible="false"
xmlns:s="library://ns.adobe.com/flex/spark" width="1024" height="75" xmlns:mx="library://ns.adobe.com/flex/mx" >
<fx:Script>
<![CDATA[
import mx.managers.PopUpManager;
import qnx.dialog.AlertDialog;
private var tele:Telestrator = new Telestrator();
private var alert:AlertDialog = new AlertDialog();
protected function btn_clickHandler(event:MouseEvent):void
{
// Figure out which button was pressed, and load appropriate view.
}
protected function onButtonInheaderbarClick(event:Event):void{
dispatchEvent(new Event('parentDoSomething'));
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:backgroundFill>
<s:SolidColor alpha="0.9" color="#000000" />
</s:backgroundFill>
<s:layout>
<s:HorizontalLayout horizontalAlign="right" verticalAlign="middle" paddingTop="5" paddingBottom="5" paddingRight="5" paddingLeft="5" gap="5"/>
</s:layout>
<s:Button id="btn_refresh" label="Refresh" height="60" fontSize="18" click="onButtonInheaderbarClick(event)"/>
<s:Label text="APPLICATION NAME" fontSize="32" styleName="FeedItemTitle" textAlign="center" width="100%" height="100%" verticalAlign="middle" />
<s:Button id="btn_about" label="About" height="60" fontSize="18" click="btn_clickHandler(event)"/>
</s:BorderContainer>
OK, still looking it over but the first mistake I see is you nested function which could be causing scoping issues so lets start with that and see if that helps.
Fix your DrawingArea class like so.
package{
import flash.display.BitmapData;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.net.FileReference;
import flash.utils.ByteArray;
import mx.core.UIComponent;
import mx.events.FlexEvent;
import mx.graphics.codec.PNGEncoder;
public class DrawingArea extends UIComponent{
private var isDrawing:Boolean = false;
private var x1:int;
private var y1:int;
private var x2:int;
private var y2:int;
public var drawColor:uint = 0x000000;
public function DrawingArea(){
this.super();
this.addEventListener(Event.ADDED_TO_STAGE, this.erase );
this.addEventListener(MouseEvent.MOUSE_DOWN, this.mouseDown);
this.addEventListener(MouseEvent.MOUSE_MOVE, this.mouseMove);
this.addEventListener(MouseEvent.MOUSE_UP, this.mouseUp);
}
private function mouseDown( e:MouseEvent ):void{
this.x1 = mouseX;
this.y1 = mouseY;
this.isDrawing = true;
}
private function mouseMove(e:MouseEvent ):void{
if (!event.buttonDown){
this.isDrawing = false;
}
this.x2 = mouseX;
this.y2 = mouseY;
if (this.isDrawing){
this.graphics.lineStyle(2, this.drawColor);
this.graphics.moveTo(this.x1, this.y1);
this.graphics.lineTo(this.x2, this.y2);
this.x1 = this.x2;
this.y1 = this.y2;
}
}
private function mouseUp( e:MouseEvent ):void{
this.isDrawing = false;
}
public function erase( e:Event ):void{
this.graphics.clear();
this.graphics.beginFill(0xffffff, 0.00001);
this.graphics.drawRect(0, 0, this.width, this.height);
this.graphics.endFill();
}
}
}
In main.mxml do this
private var child:Child;
function init(){
this.child = = new Child();
this.child.width = 100;
this.child.height = 100;
this.child.x = 10;
this.child.y = 10;
this.addChild( child );
headerMenu.addEventListener('parentDoSomething', onHeaderBarToldMeTo);
}
I have a mx.List and a mx.Tree. I'm trying to drag items from the list to the tree but instead of have them add to the actually tree itself I just want to find out what the dropTarget on the tree is. The dropTarget variable is always null.
protected function sparkTree_dragDropHandler(event:DragEvent):void
{
var source:* = event.dragInitiator;
var target:* = event.currentTarget;
trace("Dragged......", source.selectedItem.label);
trace("From.........", source.name);
trace("To...........", event.currentTarget.name);
trace("Target Item..", event.currentTarget.dropTarget);
}
Output:
Dragged...... itemOne
From......... _Main_Tree2
To........... _Main_Tree1
Target Item.. null
So just to clarify I'm trying to get the object that the items is being dropped onto.
As a side note using:
var source:List = event.dragInitiator as List;
var target:List = event.currentTarget as List;
resulted in null object reference error. Seems odd?
UPDATE:
(Not sure where the best place to post this is but) I think this may be the solution...
Create custom event: ItemDragEvent
package events
{
import mx.core.DragSource;
import mx.core.IUIComponent;
import mx.events.DragEvent;
public class ItemDragEvent extends DragEvent
{
public static const DRAG_DROP:String = "itemDragDrop";
public static const DRAG_ENTER:String = "itemDragEnter";
public static const DRAG_EXIT:String = "itemDragExit";
public var item:Object;
public var data:Object;
public var index:Object;
public function ItemDragEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=true, dragInitiator:IUIComponent=null, dragSource:DragSource=null, action:String=null, ctrlKey:Boolean=false, altKey:Boolean=false, shiftKey:Boolean=false)
{
super(type, bubbles, cancelable, dragInitiator, dragSource, action, ctrlKey, altKey, shiftKey);
}
}
}
Create an mx.Tree item renderer: TreeItemRenderer
<?xml version="1.0" encoding="utf-8"?>
<s:MXTreeItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
dragEnter="dragEnterHandler(event)"
dragExit="dragExitHandler(event)"
dragDrop="dragDropHandler(event)"
>
<fx:Script>
<![CDATA[
import events.ItemDragEvent;
import mx.core.IUIComponent;
import mx.events.DragEvent;
import mx.managers.DragManager;
protected function dragEnterHandler(event:DragEvent):void
{
DragManager.acceptDragDrop(event.currentTarget as IUIComponent);
var e:ItemDragEvent = new ItemDragEvent(ItemDragEvent.DRAG_ENTER, true);
e.data = data;
e.item = data;
e.index = itemIndex;
dispatchEvent(e);
trace("TreeItemRenderer, dragEnterHandler");
}
protected function dragExitHandler(event:DragEvent):void
{
var e:ItemDragEvent = new ItemDragEvent(ItemDragEvent.DRAG_EXIT, true);
e.data = data;
e.item = data;
e.index = itemIndex;
dispatchEvent(e);
trace("TreeItemRenderer, dragExitHandler");
}
protected function dragDropHandler(event:DragEvent):void
{
DragManager.acceptDragDrop(event.currentTarget as IUIComponent);
var e:ItemDragEvent = new ItemDragEvent(ItemDragEvent.DRAG_DROP, true);
e.data = data;
e.item = data;
e.index = itemIndex;
dispatchEvent(e);
trace("TreeItemRenderer, dragDropHandler");
}
]]>
</fx:Script>
<s:states>
<s:State name="normal" />
<s:State name="hovered" />
<s:State name="selected" />
</s:states>
<s:HGroup left="0" right="0" top="0" bottom="0" verticalAlign="middle">
<s:Rect id="indentationSpacer" width="{treeListData.indent}" percentHeight="100" alpha="0">
<s:fill>
<s:SolidColor color="0xFFFFFF" />
</s:fill>
</s:Rect>
<s:Group id="disclosureGroup">
<s:BitmapImage source="{treeListData.disclosureIcon}" visible="{treeListData.hasChildren}" />
</s:Group>
<s:BitmapImage source="{treeListData.icon}" />
<s:Label id="labelField" text="{treeListData.label}" paddingTop="2"/>
</s:HGroup>
</s:MXTreeItemRenderer>
Finally the Main code
</fx:Declarations>
<fx:Script>
<![CDATA[
import events.ItemDragEvent;
import itemRenderers.TreeItemRenderer;
import mx.collections.ArrayCollection;
import mx.events.DragEvent;
import mx.events.FlexEvent;
import mx.utils.ObjectUtil;
[Bindable]
private var listData:ArrayCollection = new ArrayCollection([ "One", "Two", "Three" ]);
[Bindable]
private var treeData:Object = { label: "First", children: new ArrayCollection([ { label: "Second" }, { label: "Third" } ]) };
protected function windowedapplication1_initializeHandler(event:FlexEvent):void
{
tree1.addEventListener(ItemDragEvent.DRAG_DROP, treeItemDragDropHandler);
}
protected function treeItemDragDropHandler(event:ItemDragEvent):void
{
event.preventDefault();
trace("ItemDragDrop:", ObjectUtil.toString(event.data));
}
]]>
</fx:Script>
<s:layout>
<s:HorizontalLayout horizontalAlign="center" verticalAlign="middle" />
</s:layout>
<mx:Tree id="list1" width="50%" height="100%"
dataProvider="{listData}" labelField="label"
dragEnabled="true"
dragMoveEnabled="true"
dropEnabled="true" />
<mx:Tree id="tree1" width="50%" height="100%"
dataProvider="{treeData}"
dragEnabled="true"
dropEnabled="true"
showRoot="true"
itemRenderer="itemRenderers.TreeItemRenderer" />
Needs a bit of work to sort out visual feedback, but that should output the Tree item that was dropped onto.
In regards to
var source:List = event.dragInitiator as List;
var target:List = event.currentTarget as List;
Try to check your imports. Maybe there was imported Spark lists but you're using MX List? :)
In regards to dropTarget property please refer to documentation about it. It doesn't relate to Flex drag-n-drop functionality. And so there is no surprise the value of this property is null.
What about your problem in general you can use the following snippet which doesn't solve all the problems (I have no time to debug all the aspects) but can provide you some good starting point:
<?xml version="1.0" encoding="utf-8"?>
<s:Application minHeight="600" minWidth="955" xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.collections.ICollectionView;
import mx.events.DragEvent;
import mx.managers.DragManager;
[Bindable]
private var listDataProvider:ArrayCollection = new ArrayCollection([ "First", "Second", "Third" ]);
[Bindable]
private var treeDataProvider:Object =
{ label: "First", children: new ArrayCollection([ { label: "Second" }, { label: "Third" } ]) };
protected function list_dragCompleteHandler(event:DragEvent):void
{
if (event.relatedObject == tree)
{
event.preventDefault();
if (event.action == DragManager.MOVE && list.dragMoveEnabled)
{
var items:Array = event.dragSource.dataForFormat("items") as Array;
var collection:ArrayCollection = list.dataProvider as ArrayCollection;
for each (var item:Object in items)
{
if (collection.contains(item))
collection.removeItemAt(collection.getItemIndex(item));
}
}
}
}
protected function tree_dragDropHandler(event:DragEvent):void
{
var source:List = List(event.dragInitiator);
var target:Tree = Tree(event.currentTarget);
trace("Dragged......", source.selectedItem);
trace("From.........", source.name);
trace("To...........", target.name);
event.preventDefault();
tree.hideDropFeedback(event);
var index:int = tree.calculateDropIndex(event);
var items:Array = new Array();
if (event.dragSource.hasFormat("treeItems"))
items = items.concat(event.dragSource.dataForFormat("treeItems") as Array);
if (event.dragSource.hasFormat("items"))
items = items.concat(event.dragSource.dataForFormat("items") as Array);
if (index > (tree.dataProvider as ICollectionView).length)
index = (tree.dataProvider as ICollectionView).length;
for each (var item:Object in items)
{
var obj:Object = new Object()
obj.label = item;
(tree.dataProvider as ArrayCollection).addItemAt(obj, index);
}
}
protected function tree_dragEnterHandler(event:DragEvent):void
{
if (event.dragInitiator == list)
{
event.preventDefault();
DragManager.acceptDragDrop(event.target as Tree);
tree.showDropFeedback(event);
}
}
protected function tree_dragExitHandler(event:DragEvent):void
{
event.preventDefault();
tree.hideDropFeedback(event);
}
protected function tree_dragOverHandler(event:DragEvent):void
{
if (event.dragInitiator == list)
{
event.preventDefault();
tree.showDropFeedback(event);
}
}
]]>
</fx:Script>
<s:layout>
<s:HorizontalLayout horizontalAlign="center" verticalAlign="middle" />
</s:layout>
<mx:List dataProvider="{listDataProvider}" dragComplete="list_dragCompleteHandler(event)" dragEnabled="true"
dragMoveEnabled="true" dropEnabled="true" id="list" width="200" />
<mx:Tree dataProvider="{treeDataProvider}" dragDrop="tree_dragDropHandler(event)" dragEnabled="true"
dragEnter="tree_dragEnterHandler(event)" dragExit="tree_dragExitHandler(event)"
dragOver="tree_dragOverHandler(event)" dropEnabled="true" id="tree" showRoot="true" width="200" />
</s:Application>
I'm working on a flash cards application and am using an ArrayCollection of Objects to store each cards individual data. When the user click the 'save' button, the text from the two textAreas and the 'title' textinput are stored in the AC as one object with .title, .side1 and .side2 properties that contain the text from the flash card.
I have made a List in a separate class I want to have display the title of each card the user has created, but after days of researching and looking around, I still cannot get the display to list the titles.
If anyone could point me in the right direction it would very appreciated.
Part of my NewCard.mxml:
<?xml version="1.0" encoding="utf-8"?>
<fx:Script>
<![CDATA[
import flash.events.EventDispatcher;
import mx.collections.ArrayCollection;
import spark.effects.SlideViewTransition;
import views.MyCards;
protected function button1_clickHandler(event:MouseEvent):void // back button
{
{
navigator.pushView(views.MyFlashCardsHome, event.relatedObject);
}
}
protected function button2_clickHandler(event:MouseEvent):void // save button
{
var myc:MyCards = new MyCards();
var card:Object = new Object();
myc.add();
titleCard.text = "Card Added!";
}
protected function button3_clickHandler(event:MouseEvent):void // flip button
{
rotateEffect.play();
if(rotateEffect.isPlaying)
{
if(mtext1.visible)
{
mtext2.visible = true;
mtext1.visible = false;
//mtext2.text = "two";
groupt.layoutDirection = "rtl";
}
else
{
mtext2.visible = false;
mtext1.visible = true;
//mtext1.text = "one";
groupt.layoutDirection = "rtl";
}
}
}
protected function button4_clickHandler(event:MouseEvent):void // push home button
{
var slideViewTransition:SlideViewTransition = new SlideViewTransition( 300, SlideViewTransition.SLIDE_RIGHT);
navigator.pushView(views.HomePage, event.relatedObject, slideViewTransition);
}
]]>
</fx:Script>
<fx:Declarations>
<s:Rotate3D id="rotateEffect" duration="300" target="{groupt}"
angleYFrom="0" angleYTo="180"
autoCenterTransform="true"
effectStart="flipButton.enabled=false;"
effectEnd="flipButton.enabled=true;"/>
</fx:Declarations>
<s:actionContent>
<s:Button height="50" label="Study" click="button1_clickHandler(event)" cornerRadius="0"
fontFamily="_sans"/>
<s:Button height="62" click="button4_clickHandler(event)" cornerRadius="0" skinClass="skins.homeButtonSkin"/>
</s:actionContent>
<s:Image x="0" y="-80" width="1024" height="600" source="#Embed('mainapp1.jpg')"/>
<s:TextInput id="titleCard" x="240" y="10" height="62" chromeColor="#515851" color="#060606"
contentBackgroundAlpha="1.0" contentBackgroundColor="#FFFFFF" text="Title"/>
<s:SkinnableContainer
id = "groupt" x="161" y="88" width="703" height="357" >
<s:TextArea id="mtext2" visible="false" x="0" y="0" width="703" height="357"
color="#000000" contentBackgroundAlpha="1.0"
contentBackgroundColor="#FFFFFF" editable="true" enabled="true"
paddingTop="70" text="Enter Text Here: (Side Two)" textAlign="center"/>
<s:TextArea id="mtext1" x="0" y="0" width="703" height="357" color="#030303"
contentBackgroundAlpha="1.0" contentBackgroundColor="#FFFFFF" editable="true"
enabled="true" fontFamily="Arial" fontStyle="normal" fontWeight="normal"
lineThrough="false" paddingTop="70" text="Enter Text Here: (Side One)"
textAlign="center" textDecoration="none" verticalAlign="middle"/>
</s:SkinnableContainer>
<s:Button x="763" y="10" height="62" label="Save" click="button2_clickHandler(event)"
cornerRadius="0" fontFamily="_sans"/>
<s:Label x="5" y="34" color="#49A6D6" fontFamily="Georgia" fontStyle="italic" fontWeight="bold"
paddingLeft="25" text="My"/>
<s:Label x="68" y="34" width="73" color="#E0B338" fontFamily="Georgia" fontStyle="italic"
fontWeight="bold" paddingLeft="0" text="Flash"/>
<s:Label x="138" y="34" color="#49A6D6" fontFamily="Georgia" fontStyle="italic" fontWeight="bold"
text="Cards!"/>
<s:Button id="flipButton" x="468" y="460" height="50" label="Flip" chromeColor="#2428D8"
click="button3_clickHandler(event)" fontFamily="_sans"/>
Part of my MyCards.mxml:
<?xml version="1.0" encoding="utf-8"?>
<fx:Script>
<![CDATA[
import flash.events.IOErrorEvent;
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import mx.collections.ArrayCollection;
import mx.collections.ArrayList;
import mx.events.CollectionEvent;
import mx.events.FlexEvent;
import spark.effects.SlideViewTransition;
import spark.events.IndexChangeEvent;
import views.NewCard;
public var file:File;
public var fileStream:FileStream;
public var fileName:String = "Initial String";
private var directory:String = "SimpleSaveFromAIR";
public var nc:NewCard = new NewCard();
public var card:Object = new Object();
[Bindable]
public var cards:ArrayCollection = new ArrayCollection();
protected function button1_clickHandler(event:MouseEvent):void // pushed home button
{
var svt:SlideViewTransition = new SlideViewTransition(300, SlideViewTransition.SLIDE_RIGHT);
navigator.pushView(views.HomePage, event.relatedObject, svt);
}
public function add():void
{
var nc:NewCard = new NewCard();
var card:Object = new Object();
card.fTitle = nc.titleCard.text; //adding text to object from NewCard.mxml class
cards.addItem(card);
}
/* public function save():void
{
file = File.documentsDirectory.resolvePath(directory + "/" + fileName);
fileStream = new FileStream();
fileStream.open(file, FileMode.WRITE);
fileStream.writeObject(cards);
fileStream.close();
} */
public function myCardsList_creationCompleteHandler(event:FlexEvent):void
{
cards.addEventListener(CollectionEvent.COLLECTION_CHANGE, refreshList);
trace(cards.list); // no data at all shows up here
}
private function refreshList(event:CollectionEvent):void
{
trace("cards refreshed "+ cards.list);
}
public function testButton_clickHandler(event:MouseEvent):void
{
card.fTitle = nc.titleCard.text;
cards.addItem(card);
//trace(cards.list); // add data that has been added shows up here
}
]]>
</fx:Script>
<s:actionContent>
<s:Button id="testButton" label="Button" click="testButton_clickHandler(event)" />
<s:Button label="Delete"/>
<s:Button label="Home" click="button1_clickHandler(event)" skinClass="skins.homeButtonSkin"/>
</s:actionContent>
<s:Image x="0" y="-80" height="603" source="mainapp1.jpg"/>
<s:List id="myCardsList" x="10" y="10" left="0" right="0" top="0" bottom="0" width="1004"
height="500" dataProvider="{cards}" labelField="fTitle"
enabled="true" >
</s:List>
Again any help is greatly appreciated.
CardVO class:
package
{
public class CardVO
{
private var _title:String; //values returned from getter/setter functions
private var _side1:String;
private var _side2:String;
//get the "Title", "Side1" and "Side2" values from textAreas (later) and set them
// above variables
public function get Title():String {return _title;}
public function set Title(value:String):void { _title = value; }
public function get Side1():String {return _side1;}
public function set Side1(value:String):void {_side1 = value;}
public function get Side2():String {return _side2;}
public function set Side2(value:String):void {_side2 = value;}
}
}
** NewCard snippet:**
[Bindable]
public var myCard:CardVO = new CardVO(); // create new instance of CardVO
....
<!-- text property of mtext1 and mtext2 is bound and returned to the get/set functions in CardVO in the 'change' event-->
<!-- change sets setter values to those retrieved from textAreas-->
<s:TextArea id="mtext2" visible="false" x="0" y="0" width="703" height="357"
color="#000000" contentBackgroundAlpha="1.0"
contentBackgroundColor="#FFFFFF" editable="true" enabled="true"
paddingTop="70" text="{myCard.Side2}" change = "{myCard.Side2 = mtext2.text}"
textAlign="center"/>
<s:TextArea id="mtext1" x="0" y="0" width="703" height="357" color="#030303"
contentBackgroundAlpha="1.0" contentBackgroundColor="#FFFFFF" editable="true"
enabled="true" fontFamily="Arial" fontStyle="normal" fontWeight="normal"
lineThrough="false" paddingTop="70" text="{myCard.Side1}" change="{myCard.Side1 = mtext1.text}"
textAlign="center" textDecoration="none" verticalAlign="middle"/>
</s:SkinnableContainer>
MyCards snippet:
public function add():void
{
var nc:NewCard = new NewCard(); // create new instance of NewCard
cards.addItem(nc.myCard); // add new Item to ArrayCollection 'cards'
trace(cards.list);
}
Mycards List code
<s:List id="myCardsList" x="10" y="10" left="0" right="0" top="0" bottom="0" width="1004"
height="500" change="myCardsList_changeHandler(event)" dataProvider="{cards}"
enabled="true" >
<s:itemRenderer>
<fx:Component>
<s:MobileItemRenderer label="{data.title}"/>
</fx:Component>
</s:itemRenderer>
</s:List>
Assuming you're using the List component you should be able to specify the field you want to show using the labelField property.
<s:List id="myFlashCardList" dataProvider="{cards}" labelField="fTitle"/>
EDIT 2:
It seems like what you're trying to do here (and correct me if I'm wrong), is to have the user create a new instance of the NewCard object and then add it to your cards ArrayCollection. Your list then displays the titles of the cards the user has created.
Assuming this is the case, I think you're making it a little complicated than it needs to be. ArrayCollections can hold any type of class or object so you don't have to create a new Object and add it to the ArrayCollection every time they add a new card.
What I would do is create a Card class and populate it using your NewCard component. When you're done, you add that Card class to the ArrayCollection. Something like this:
The CardVO class:
package
{
public class CardVO
{
private var _title:String;
private var _side1:String;
private var _side2:String;
public function get Title():String { return _title; }
public function set Title(value:String):void { _title = value; }
public function get Side1():String { return _side1; }
public function set Side1(value:String):void { _side1 = value; }
public function get Side2():String { return _side2; }
public function set Side2(value:String):void { _side2 = value; }
}
}
Then in your NewCard.mxml file you use a CardVO to store the data:
<fx:Script>
<![CDATA[
...
[Bindable] public var myCard:CardVO = new CardVO();
...
]]>
</fx:Script>
<s:SkinnableContainer id = "groupt">
<s:TextArea id="mtext2" text="{myCard.Side2}" change="{myCard.Side2 = mtext2.text}"/>
<s:TextArea id="mtext1" text="{myCard.Side1}" change="{myCard.Side1 = mtext1.text}" />
</s:SkinnableContainer>
Then after the user has created their card, you pass the CardVO object to your ArrayCollection.
...
public function add():void
{
var nc:NewCard = new NewCard();
cards.addItem(nc.myCard);
}
...
This is a very abbreviated example so feel free to ask any questions that don't make sense. You should also look into Data Binding if you haven't already done so. It will save you a lot of time and make your apps more efficient once you get the hang of it. :)
I want to set the enabled property on a button based on the return value of a function that has one or more parameters. How can I do this?
private function isUserAllowed (userName:Boolean):Boolean {
if (userName == 'Tom')
return true;
if (userName == 'Bill')
return false;
}
<mx:Button label="Create PO" id="createPOButton"
enabled="<I want to call isUserAllowed ('Bill') or isUserAllowed ('Tom') here>"
click="createPOButton_Click()" />
According to the Flex docs, as long as the property is bindable, you can simply do this (I've included the two extra buttons to demonstrate):
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
[Bindable]
private var currentUser:String = "Bill";
private function isUserAllowed(user:String):Boolean
{
if (user == "Bill")
{
return true;
}
return false;
}
]]>
</mx:Script>
<mx:VBox>
<mx:Button label="My Button" enabled="{isUserAllowed(currentUser)}" />
<mx:HBox>
<mx:Button label="Try Tom" click="{currentUser = 'Tom'}" />
<mx:Button label="Try Bill" click="{currentUser = 'Bill'}" />
</mx:HBox>
</mx:VBox>
</mx:Application>
Without currentUser marked [Bindable], though, it won't work.
Another way to go, if you wanted to bind more literally to the function (this is also expressed in the docs), would be to have the function respond to an event you dispatch when the current user changes, like so:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="init()">
<mx:Script>
<![CDATA[
private var _currentUser:String = "Bill";
public function set currentUser(value:String):void
{
if (_currentUser != value)
{
_currentUser = value;
dispatchEvent(new Event("userChanged"));
}
}
[Bindable(event="userChanged")]
private function isUserEnabled():Boolean
{
if (_currentUser == "Bill")
{
return true;
}
return false;
}
]]>
</mx:Script>
<mx:VBox>
<mx:Button label="My Button" enabled="{isUserEnabled()}" />
<mx:HBox>
<mx:Button label="Try Tom" click="{currentUser = 'Tom'}" />
<mx:Button label="Try Bill" click="{currentUser = 'Bill'}" />
</mx:HBox>
</mx:VBox>
</mx:Application>
So there are a couple of ways. IMO, the second seems somehow more proper, but there's definitely nothing wrong with the first. Good luck!
<mx:Button
enabled = "{this.myFunction(this.myVariable)}"
>
or inline:
<mx:Button
enabled = "{(function(arg:Object):Boolean{ ... })(this.myVariable)}"
>
Here's what I've done a few times in similar circumstances:
<mx:Script>
<![CDATA[
[Bindable] var _username : String;
private function isUserAllowed (userName:Boolean):Boolean {
if (userName == 'Tom')
return true;
if (userName == 'Bill')
return false;
}
]]>
</mx:Script>
<mx:Button label="Create PO"
id="createPOButton"
enabled="{isUserAllowed(_username)}"
click="createPOButton_Click()" />
This way, when the Bindable _username changes, it will fire a change notification. Since the label is listening to _username changes (even if it is simply a parameter to another function), the enabled property will be re-evaluated.
<mx:Script>
<![CDATA[
[Bindable]
private var userName : String = "Tom"; // or whatever ...
[Bindable]
private var userAllowed : Boolean;
private function isUserAllowed ():Boolean {
if (userName == 'Tom')
return false;
if (userName == 'Bill')
return false;
return false;
}
]]>
</mx:Script>
<mx:Button label="Create PO" id="createPOButton" enabled="{userAllowed}" addedToStage="isUserAllowed()"/>