Can I write a function inside an attribute in flex? Something like this:
<s:Button id="btn" label="text" visible="{foo()}"/>
private function foo():Boolean
{
//do something
}
It seems it doesn't work at least for me.
I know that I can write like visible="{something == true && somethingElse == false}" etc. But I need it to do more like for loops etc.
Try this:
[Bindable(event="update")]
private function foo():Boolean
{
return a && b && c;
}
and when a or b or c is change just do this:
dispatchEven(new Event("update"));
This implementation is not bindable - if the result of foo() changes, it will not be reflected on your display list.
Although, I think this should work once upon creation complete:
<?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">
<fx:Script>
<![CDATA[
private function foo():Boolean
{
return false;
}
]]>
</fx:Script>
<s:Button label="text"
visible="{foo()}" />
</s:Application>
A better approach would be to incorporate a presentation model, leveraging binding as seen here:
<?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="creationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
[Bindable]
public var presentationVisible:Boolean = true;
private var timer:Timer = new Timer(500);
private function foo():void
{
presentationVisible = Math.random() > 0.5 ? true : false;
}
protected function creationCompleteHandler(event:FlexEvent):void
{
timer.addEventListener(TimerEvent.TIMER, timerHandler);
timer.start();
}
protected function timerHandler(event:TimerEvent):void
{
foo();
}
]]>
</fx:Script>
<s:Button label="text"
visible="{presentationVisible}" />
</s:Application>
Related
I had a code like this
var str:string = "GeoCode: 3";
in this code I want ":" to be in bold.
How can I do that and this should be done in spark
Please help me
Thanks!
The simplest approach is to use TextFlowUtil.importFromString() and assign the resulting TextFlow object to a RichText component, like this:
<s:RichText id="textDisplay"/>
textDisplay.textFlow =
TextFlowUtil.importFromString('GeoCode<span fontWeight="bold">:</span> 3');
If you'd like to keep your original Strings intact, you can do a replace on them to add the span:
var str:String = "GeoCode: 3";
str = str.replace(/:/, '<span fontWeight="bold">:</span>');
textDisplay.textFlow = TextFlowUtil.importFromString(str);
I would do something like this:
The text property of the component is splitted into parts by means of ":" symbol. Then each part is added into a HGroup like a Label. Colons are added bold.
//Application
<?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" xmlns:com="com.*">
<s:VGroup left="20" top="20">
<com:GeoLabel text="GeoCode: 3"/>
<com:GeoLabel text="GeoCode: 5: Some Info: 123"/>
</s:VGroup>
</s:Application>
//GeoLabel component
<?xml version="1.0" encoding="utf-8"?>
<s:HGroup 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="120" height="25" gap="0">
<fx:Script>
<![CDATA[
import spark.components.Label;
private var _text:String;
public function get text():String
{
return _text;
}
public function set text(value:String):void
{
_text = value;
createMembers();
}
private function insertLabel(str:String, bold:Boolean):void
{
var la:Label = new Label();
la.text = str;
if (bold)
la.setStyle("fontWeight", "bold");
this.addElement(la);
}
private function createMembers():void
{
this.removeAllElements();
var arr:Array = text.split(":");
for (var i:int = 0; i < arr.length; i++)
{
if (i != 0)
insertLabel(":", true);
insertLabel(arr[i], false);
}
}
]]>
</fx:Script>
</s:HGroup>
I just started working with Flex. I know it's pathetic but it's a long story.
Now, the problem I am facing is that I have a list component which has a dataprovider on it. What I would like to do is when an item on the list is clicked I would like to have a check sign right next to the label.
Below is the component:
<s:List id="tabList" width="100%"
borderVisible="false" click="tabList_clickHandler(event)"
selectedIndex="{this.hostComponent.selectedIndex}"
itemRenderer="MultiTabListRenderer" />
Below is the Itemrenderer code:
protected function AddCheck_clickHandler(event:MouseEvent):void {
// TODO Auto-generated method stub
var checkLabel:Label;
checkLabel = new Label();
checkLabel.text = "checkMark";
var e: ItemClickEvent = new ItemClickEvent(ItemClickEvent.ITEM_CLICK, true);
e.item = data;
e.index = itemIndex;
dispatchEvent(e);
this.checkRectGroup.addElementAt(checkLabel, e.index);
}
<s:Label id="customMultitabList" text="{data.label}"
left="10" right="0" top="6" bottom="6" click="AddCheck_clickHandler(event)"/>
My code inside the function is wrong which is mainly due to the fact that I do not understand each and everything in flex. I am not in a mood to learn the language in detail because it's not a long term work for me. Also, in the renderer file when I use s:List instead of s:label I do not see the labels anymore. Of course I replace the attribute text with dataprovider={data.selectedItem}.
One way to approach this is to add a field to the objects in your dataProvider that tracks whether or not the item has been selected.
Then, in your item renderer, you inspect this field and decide whether or not to display the checkmark. Here's a working example app and renderer:
Application:
<?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" xmlns:local="*"
creationComplete="application1_creationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.events.CollectionEvent;
import mx.events.CollectionEventKind;
import mx.events.FlexEvent;
import mx.events.PropertyChangeEvent;
import mx.events.PropertyChangeEventKind;
private var collection:ArrayCollection;
protected function application1_creationCompleteHandler(event:FlexEvent):void
{
collection = new ArrayCollection([
{ label: 1, selected: false },
{ label: 2, selected: false },
{ label: 3, selected: false }]);
listbert.dataProvider=collection;
}
protected function listbert_clickHandler(event:MouseEvent):void
{
var index:int = listbert.selectedIndex;
var item:Object = listbert.selectedItem;
item.selected = !item.selected;
// Create these events because the items in the ArrayCollection
// are generic objects. It shouldn't be necessary if items in
// your collection are a Class that extends EventDispatcher
// see ArrayList::startTrackUpdates()
var e:PropertyChangeEvent = new PropertyChangeEvent(
PropertyChangeEvent.PROPERTY_CHANGE, false,false,
PropertyChangeEventKind.UPDATE, 'selected', !item.selected,
item.selected, item);
collection.dispatchEvent(new CollectionEvent(
CollectionEvent.COLLECTION_CHANGE, false,false,
CollectionEventKind.UPDATE, index, index, [e]));
}
]]>
</fx:Script>
<s:List id="listbert" click="listbert_clickHandler(event)" itemRenderer="TestRenderer"/>
</s:Application>
Item 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" >
<fx:Script>
<![CDATA[
override public function set data(value:Object):void
{
super.data = value;
labelDisplay.text = value.label;
if (value.selected)
checkMarkLabel.text = "✓";
else
checkMarkLabel.text = "";
}
]]>
</fx:Script>
<s:layout>
<s:HorizontalLayout/>
</s:layout>
<s:Label id="labelDisplay" />
<s:Label id="checkMarkLabel" />
</s:ItemRenderer>
I have a Flex application which sends a query to a database when an user clicks a button. Since the query might be heavy, and can take up to a minute, I want to display an alert, which will close only after an event comes back from the database (user won't be able to close it himself). Is it possible in Flex? How do I do that?
I have functions sendQuery() and dataEventHandler(). I think I need to put code in sendQuery() to display the alert and in dataEventHandler() to close it after data comes from the DB, but how do I make the alert "unclosable" by the user?
The built in Flex Alert class will always have some type of close button.
However, there is no reason you can't create your own component; and then open and close it using the PopUpManager.
Following code may help you… (One of the solution...)
You can find I have made Solution 1 and Solution 2… You can use any one of it and third solution is to create your own Custom Component.
Please find below code…. You can use below logic to solve your problem..
Use Timer to check if data received or you can dispatch custom event and call updateAlertPosition function.
Hope it may help: -
<?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"
>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.CloseEvent;
import mx.managers.PopUpManager;
private var minuteTimer:Timer;
private var alert:Alert;
private var displayInitialText:String = "Data Not Received, Please wait....";
private var displayDataReveivedText:String = "Data Received...";
private function timerInit():void
{
//Logic to check if data Received.
minuteTimer = new Timer(3000);
minuteTimer.addEventListener(TimerEvent.TIMER, updateAlertPosition);
minuteTimer.start();
}
private function updateAlertPosition(event:Event = null):void {
minuteTimer.stop();
//Solution 1
//add your flag here if y you want to check if data is received or not
//if(Data Received)
alert.mx_internal::alertForm.mx_internal::buttons[0].enabled = true;
alert.mx_internal::alertForm.mx_internal::buttons[1].enabled = true;
alert.mx_internal::alertForm.mx_internal::textField.text = displayDataReveivedText;
//Solution 2
//alert.enabled = true;
//If you want to remove it automatically
//closeAutomatically();
}
private function closeAutomatically():void
{
PopUpManager.removePopUp(alert);
}
private function clickHandler():void
{
//Start Timer
timerInit();
//Solution 1
alert = Alert.show(displayInitialText, "Alert", Alert.OK|Alert.CANCEL,this,alertCloseHandler);
alert.mx_internal::alertForm.mx_internal::buttons[0].enabled = false;
alert.mx_internal::alertForm.mx_internal::buttons[1].enabled = false;
//Solution 2
//alert.enabled = false;
}
private function alertCloseHandler(event:CloseEvent):void
{
if(event.detail == Alert.CANCEL)
{
//Some Code on close
}
else
{
//Some Code on OK
}
}
]]>
</fx:Script>
<s:Button label="Show Alert" x="100" y="100" click="clickHandler()"/>
</s:Application>
make a 0-0.2 alpha shape what covers the whole application (probably you'll want to listen for resizeevents), and add a custom panel to the middle of it, with the message.
As an idea you can create a custom alert then:
Show Alert
Disable Application.
Hide Alert.
Enable Application.
An alert example:
<?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"
creationComplete="onCreationComplete(event)">
<s:Rect>
<s:fill>
<s:SolidColor color="0xFFFFFF"/>
</s:fill>
<s:stroke>
<s:SolidColorStroke />
</s:stroke>
</s:Rect>
<s:Label text="Please Wait..."/>
<fx:Script>
<![CDATA[
import mx.core.FlexGlobals;
import mx.events.FlexEvent;
import mx.managers.PopUpManager;
public static function show():void
{
PopUpManager.createPopUp(FlexGlobals.topLevelApplication);
}
public static function hide():void
{
PopUpManager.removePopUp(this);
FlexGlobals.topLevelApplication.enabled = true;
}
protected function onCreationComplete(event:FlexEvent):void
{
PopUpManager.centerPopUp(this);
FlexGlobals.topLevelApplication.enabled = false;
}
]]>
</fx:Script>
</s:Group>
Usage:
YourAlert.show();
YourAlert.hide();
#Alex, I used your code but modify it a bit, because there was some errors:
<?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"
creationComplete="creationCompleteHandler()" width="100%" height="100%">
<fx:Script>
<![CDATA[
import mx.core.FlexGlobals;
import mx.core.UIComponent;
import mx.managers.PopUpManager;
///////////////////////////////////////
//// public functions - my group is ImageViewer.mxml component
public static function show():ImageViewer {
return PopUpManager.createPopUp(FlexGlobals.topLevelApplication as DisplayObject, ImageViewer) as ImageViewer;
}
public function hide():void {
PopUpManager.removePopUp(this);
FlexGlobals.topLevelApplication.enabled = true;
}
////////////////////////////
//// component events
private function creationCompleteHandler():void {
PopUpManager.centerPopUp(this);
FlexGlobals.topLevelApplication.enabled = false;
}
]]>
</fx:Script>
</s:Group>
And call it like:
var imageviewer:ImageViewer = ImageViewer.show();
//imageviewer.imageURL = _value_dto.value;
Flex Actionscript question.
I have a calloutbutton that is moving on the screen.
When I open the dropdown (by a click) it stays at the same position on the screen (only the arrow is moving). It does not follow the calloutbutton's position
I would like this dropdown to follow the position of the calloutbutton when it has moved (as it does when one clicks on the button again when it has moved).
I have tried to dispatch a MouseEvent.CLICK. It does not work.
Tried also to open, then close again dropdown with actionscript sing closeDropDown() and openDropDown(). No change.
Thanks
Sample code (call init() from creationComplete) :
creationComplete="init();">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import flash.events.MouseEvent;
import mx.events.DropdownEvent;
private function init():void {
var minuteTimer:Timer = new Timer(1*1000);
minuteTimer.addEventListener(TimerEvent.TIMER, updateCalloutPosition);
// starts the timer ticking
minuteTimer.start();
}
private function updateCalloutPosition(event:Event):void {
myButton.closeDropDown();
myButton.x = this.width * Math.random();
myButton.y = this.height * Math.random();
// myButton.openDropDown();
myButton.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
}
protected function myButton_clickHandler(event:MouseEvent):void
{
if (myButton.isPopUp) {
myButton.closeDropDown();
}
else {
myButton.openDropDown();
}
}
]]>
</fx:Script>
<s:CalloutButton id="myButton" click="myButton_clickHandler(event)">
</s:CalloutButton>
I tried some workaround but openDuration and closeDuration is not working for DropDownList if it can be achieved than following code may help you. Hope following code may help you.
<?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 -->
<s:ArrayCollection id="ac">
<fx:String>AK</fx:String>
<fx:String>AL</fx:String>
<fx:String>AR</fx:String>
</s:ArrayCollection>
</fx:Declarations>
<fx:Style>
#namespace s "library://ns.adobe.com/flex/spark";
#namespace mx "library://ns.adobe.com/flex/halo";
s|DropDownList {
openDuration: 0;
closeDuration: 0;
}
</fx:Style>
<fx:Script>
<![CDATA[
import flash.events.MouseEvent;
import spark.components.supportClasses.DropDownListBase;
import spark.components.supportClasses.TextBase;
import spark.events.DropDownEvent;
import spark.skins.spark.DropDownListSkin;
import spark.utils.LabelUtil;
private var storeVisible:Boolean = false;
private function init():void {
var minuteTimer:Timer = new Timer(1*1000);
minuteTimer.addEventListener(TimerEvent.TIMER, updateCalloutPosition);
minuteTimer.start();
}
private function updateCalloutPosition(event:Event = null):void {
myButton.x = this.width * Math.random();
myButton.y = this.height * Math.random();
if(myButton.isDropDownOpen)
{
myButton.closeDropDown(false);
storeVisible = true;
}
}
private function updateComp():void
{
if(storeVisible)
{
myButton.openDropDown();
storeVisible = false;
}
}
]]>
</fx:Script>
<s:DropDownList id="myButton" selectedIndex="0" dataProvider="{ac}" updateComplete="updateComp()"/>
</s:Application>
If I execute the code below in FlashBuilder, I get the following error (I translate it)
TypeError: Error #1009: Access to an Attribute or Method of an null-Object is not possible.
at components::NumDisplay()[\src\components\NumDisplay.mxml:39]
This line in NumDisplay.mxml is the problem:
[Bindable]
public var oneled_top:OneDisplay = new OneDisplay(numberData.led_top);
If i change it from the above to:
[Bindable]
public var oneled_top:OneDisplay = new OneDisplay(1);
It is working, because I send a real Number.
So how can I access the value from numberData.led_top?
If I test the access in the samefile NumDisplay.mxml with the line
<s:Label text="{numberData.led_top}" color="#FF0000">
</s:Label>
it accesses the value, the same as if I put it in my component
<components:oneLedDisplay showData="{numberData.led_top}" x="10" y="10" />
I don't get it after searching a couple of hours...
Thanks in advance.
My main method tasachenrechner.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" minWidth="600" minHeight="500" xmlns:components="components.*">
<fx:Script>
<![CDATA[
import components.NumberDisplay;
[Bindable]
protected var firstNumber:NumberDisplay = new NumberDisplay(1);
[Bindable]
protected var secondNumber:NumberDisplay = new NumberDisplay(2);
]]>
</fx:Script>
<components:NumDisplay
numberData="{firstNumber}"
x="10"
y="20"/>
<components:NumDisplay
numberData="{secondNumber}"
x="73"
y="20"/>
</s:Application>
My AS-Class NumberDisplay.as:
package components
{
import flash.display.DisplayObject;
[Bindable]
public class NumberDisplay
{
public var num:Number;
public var led_top:Number=0;
public var led_r1:Number=0;
public var led_r2:Number=0;
public var led_middle:Number=0;
public var led_l1:Number=0;
public var led_l2:Number=0;
public var led_bottom:Number=0;
public function NumberDisplay(num:Number)
{
this.num = num;
switch(this.num)
{
case 0:
trace("ZERo");
break;
case 1:
led_top = 1;
led_r1 = 1;
led_r2 = 1
trace("EINS" + led_top + " num:" + num);
break;
//[... some more cases]
default:
break;
}
}
}
}
My NumDisplay.mxml:
<?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="45" height="59"
xmlns:components="components.*">
<fx:Style>
#namespace s "library://ns.adobe.com/flex/spark";
#namespace mx "library://ns.adobe.com/flex/mx";
#namespace components "components.*";
</fx:Style>
<fx:Script>
<![CDATA[
import components.NumberDisplay;
import components.OneDisplay;
[Bindable]
public var numberData:NumberDisplay;
[Bindable]
public var oneled_top:OneDisplay = new OneDisplay(numberData.led_top);
// some more init calls of data-objects same type
]]>
</fx:Script>
<s:Label text="{numberData.led_top}" color="#FF0000">
</s:Label>
<components:oneLedDisplay showData="{oneled_top}" x="10" y="10" />
// some more objects of same type
</s:Group>
My AS-Class OneDisplay.as:
package components
{
import flash.display.DisplayObject;
public class OneDisplay
{
[Bindable]
public var show:Number;
[Bindable]
public var value:Number=0;
public function OneDisplay(show:Number)
{
this.show = show;
switch(this.show)
{
case 0:
value = 0.3;
trace(value);
break;
case 1:
value = 1.0;
trace(value);
break;
}
}
}
}
My oneLedDisplay.mxml:
<?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">
<fx:Script>
<![CDATA[
import components.OneDisplay;
[Bindable]
public var showData:OneDisplay;
]]>
</fx:Script>
<s:Rect id="stroke" width="40" height="6" alpha="{showData.value}">
<s:fill>
<s:SolidColor color="#000000"/>
</s:fill>
</s:Rect>
<s:Label text="{showData.value}" color="#FF0000">
</s:Label>
</s:Group>
Remember that you are not only assigning a value, but declaring the member variable oneled_top. At that point, you cannot access numberData because it has not been instantiated (there is no call to new NumberData()! You have to find a way to make your call to new OneDisplay (numberData.led_top) at a later time, when there actually is a value to access.
You provided lots of code which I don't want to reverse engineer.
The answer is that oneled_top is being initialized before numberData. You have no control over initialization of variables when using MXML.
Set default values in the commitProperties() method, or if oneled_Top is supposed to be a skin part, set the default values in the PartAdded method.
You'll benefit from reading up on the Component Lifecycle.
You can use BindingUtils.bindSetter() to detect changes to numberData and then initialize oneled_top
BindingUtils.bindSetter(_setOneLabel_top, this, "numberData");
and setter:
function _setOneLabel_top(disp:NumberDisplay):void
{
/* if(this.oneled_top == null) */
this.oneled_top = new OneDisplay(disp.led_top);
}
But I think, that u're using [Bindable] where you shouldn't have to need it.