Using image while creating custom components in flex - actionscript-3

For my AIR based application I am trying to create a custom component based on canvas which has an image (as shown below).
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="100" height="100" cornerRadius="5" borderStyle="solid" borderThickness="2" dropShadowEnabled="true" borderColor="#EDEDE8" dropShadowColor="#dddddd" shadowDistance="5" shadowDirection="center">
<mx:Script>
<![CDATA[
public var path:String = "";
]]>
</mx:Script>
<mx:Image id="tileImage" maintainAspectRatio="false" buttonMode="true" useHandCursor="true" source="{path}" width="100%" x="0" height="100%" y="0"/>
<mx:Canvas left="3" top="3" bottom="3" right="3" borderStyle="solid" cornerRadius="5" borderThickness="1" borderColor="#EDEDE8" alpha="0.75">
</mx:Canvas>
I am binding the source of the image with the public variable path. And when I am trying to place this component in my main mxml file like below and provide the 'path' to it, I am unable to see any image loading in the custom component. It remains blank.
var component:MyCustComponent = new MyCustComponent();
component.path = 'path/to/image.jpg';
addChild(component);
As a work around, I am trying to add an creationComplete listener to the canvas in my custom component and used to give titleImage.source = this.path . This made it work correctly but it doesn't help me if I have to keep changing the image or when the path of the image fetched using some async call. So, I would like to know if there's any alternative to fix this problem.
Thanks!!

Looks like you are just missing the bindable metatag for path. for your path declaration try:
[Bindable]
public var path:String;

Related

Actionscript 3 setStyle is not a function

I am trying to style a Flex 4 GridItem using actionscript, I have tried the following:
<mx:VBox
height="878" width="1920"
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:s="library://ns.adobe.com/flex/spark" xmlns:local="*" creationComplete="addStyles()">
<mx:Script>
<![CDATA[
public var selectedLot:String = "";
private function addStyles():void
{
testBorder.setStyle("borderThickness", "3");
}
but I get the following error:
setStyle is not a function.
Am I missing something?
The GridItem is inside a repeater.
Here is my GridItem:
<mx:GridItem id="testBorder" width="101" height="52.25" horizontalAlign="center" verticalAlign="middle" borderStyle="solid" borderColor="gray">
<mx:Image source="assets/ruler-icon.png" />
<s:Label text="{r.currentItem.sqft}" fontSize="10" color="#808080" fontFamily="Helvetica" />
</mx:GridItem>
When using a repeater the GridItem's id will not be the same. To access any item inside a repeater you have to specify an index which is correspondent to the repeated item.
Example: Array consists of ["Audi", "BMW"], we set this array to your repeater's dataProvider, then to access "Audi"'s grid item and set its style, we have to use:
testBorder[0].setStyle("borderThickness", "3");
Additionally, an important point to consider, the VBox "creationComplete" can be executed before the repeater is fully built, therefore, the best place to call your function "addStyles" is in the repeater's "repeatEnd" event i.e (repeatEnd="setTransactionPropertyType()").
Hope this helps,
Goodluck.

Dynamically generated MXML data doesn't get rendered

So I have a requirement to display dynamically generated data in the view.
For this, my idea was to create a mxml file and then use it as an object. Fill the data in the ibject and then use addChild to display it. But even after adding all the data. The dynamically generated mxml file doesn't gets displayed.
Code
BuyTogetherGrid.MXML
<?xml version="1.0" encoding="utf-8"?>
<mx:Box xmlns:mx="http://www.adobe.com/2006/mxml" width="80" height="60" xmlns:image="org.commodity.detail.image.*">
<mx:HBox>
<image:ImageBox id="buyTogetherImg"></image:ImageBox>
<mx:VBox id="textInfo">
<mx:Box id="commonNameBox">
<mx:Label id="commonName">
</mx:Label>
</mx:Box>
<mx:Box id="commonPriceBox">
<mx:Label id="commonPrice">
</mx:Label>
</mx:Box>
</mx:VBox>
</mx:HBox>
<mx:Script>
<![CDATA[
public function createGrid():void{
this.buyTogetherImg = new ImageBox();
this.commonName = new Label();
this.commonPrice = new Label();
}
]]>
</mx:Script>
</mx:Box>
This is my MXMl File. My idea was to create an object of this mxml object. Add data to buyTogetherImg, CommonName, CommonPrice and then use addChild
Part where I set the data
<mx:HBox id="buyTogetherBox" width="100%" borderColor="black">
</mx:HBox>
The upper HBox is the container where I will keep all my generated object
var buyTogetherBox : BuyTogetherGrid = new BuyTogetherGrid();
buyTogetherBox.createGrid();
for each(var item:cmListItem in commod.items){
if(item.dataFormat == 2){
buyTogetherBox.buyTogetherImg.imgData = item.value as ImageData;
} else if(item.dataFormat == 0){
buyTogetherBox.commonName.text = item.value.toString();
} else if(item.dataFormat == 3){
buyTogetherBox.commonPrice.text = StringUtil.numToStrPrice(item.value as Number);
}
}
this.buyTogetherBox.addChild(buyTogetherBox);
}
The code check some conditions and add the data. However the buyTogetherBox is not visible. But if I try something like
this.buyTogetherBox.addChild(buyTogetherBox.buyTogetherImg);
then i can see the image in the H:Box.
I am pretty new to Flex. so may be I would have missed something
You are leaving the statically created instances of the label and image control unused and creating new instances instead. Basically, the entire createGrid() function is unnecessary. You already have the controls created in MXML. Just use them with creating new instances.
var grid:BuyTogetherGrid = new BuyTogetherGrid();
grid.addEventListener(FlexEvent.CREATION_COMPLETE, this.grid_creationCompleteHandler);
Elsewhere in the same class...
private function grid_creationCompleteHandler(event:FlexEvent):void
{
// Set your properties here
}
As Pranav said it takes some time to create MXML components and if you try to assess them immediately you will get a null pointer exception because they don't exist yet. A quick and dirty solution is to make public variables in your BuyTogetherGrid.MXML and then bind the text properties to these variables, like
<?xml version="1.0" encoding="utf-8"?>
<mx:Box xmlns:mx="http://www.adobe.com/2006/mxml" width="80" height="60" xmlns:image="org.commodity.detail.image.*">
<fx:Script>
<![CDATA[
[Bindable] public var imageData:ImageData;
[Bindable] public var name:String;
[Bindable] public var price:String;
]]>
</fx:Script>
<mx:HBox>
<image:ImageBox id="buyTogetherImg" imgData={imageData}/>
<mx:VBox id="textInfo">
<mx:Box id="commonNameBox">
<mx:Label id="commonName" text="{name}">
</mx:Label>
</mx:Box>
<mx:Box id="commonPriceBox">
<mx:Label id="commonPrice" text="{price}">
</mx:Label>
</mx:Box>
</mx:VBox>
and then you do
buyTogetherBox.imageData = yourImageData;
buyTogetherBox.name = "Your Name";
buyTogetherBox.imageData = "Your price";
and yes, remove the unnecessary createGrid() method

SkinnablePopUpContainer not destroyed

I am monitoring my internet connection. When there is no service available I get an Event from my URLMonitor. I am listening to this event and calling a function that opens a SkinnablePopUpContainer. It is a very simple Component I have no listeners attached to it and it is defined only inside the function. When the user clicks the button inside the SkinnablePopUpContainer I close the component and try to destroy it using all possible ways I know of. When I check the Profiler Tool from Flash Builder the SkinnablePopUpContainer is still there. How do I destroy this component freeing the memory it is using.
Here is the listener function:
protected function onNoServiceAvailable(e:*):void
{
var noserviceWindow:NoInternetError = new NoInternetError();
noserviceWindow.open(this,false);
noserviceWindow.x= 0;
noserviceWindow.y= 0;
noserviceWindow.width = SharedObject.getLocal('localObj').data.appMeasures.appWidth;
noserviceWindow.height = SharedObject.getLocal('localObj').data.appMeasures.appHeight+200;
}
and here is my SkinnablePopUpContainer
<?xml version="1.0" encoding="utf-8"?>
<s:SkinnablePopUpContainer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:nxTextInput="nx.components.extended.nxTextInput.*"
xmlns:nxButton="nx.components.extended.nxButton.*"
backgroundAlpha="0.4"
horizontalCenter="0" verticalCenter="0" width="100%" height="100%">
<fx:Script>
<![CDATA[
protected function loginButton_clickHandler(event:Event):void
{
loginButton.removeEventListener(MouseEvent.CLICK,loginButton_clickHandler);
this.close();
var ob = this;
ob = null;
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:Panel title="Fehler"
horizontalCenter="0" verticalCenter="0" color="white">
<s:VGroup horizontalAlign="center" verticalAlign="middle" gap="20"
height="100%" width="100%">
<s:BitmapImage source="#Embed('assets/nxInspect/mobile/assetsCI/redAssets/alert_80x80.png')" id="iconBitmpapDownOnline" verticalCenter="0" />
<s:Label id="serviceFailure" text="Keine internetverbindung." width="90%" styleName="interactable" textAlign="center" color="white"/>
<nxButton:NxButton id="loginButton" label="OK" width="100%" height="100" click="loginButton_clickHandler(event)" styleName="alert"/>
</s:VGroup>
</s:Panel>
First off, the line var ob = this; just creates a reference variable to "this". Setting this variable to null will not make it delete itself. It will just re-reference the variable you just created to null again, so those 2 lines are useless.
Because you've contained your local variable noserviceWindow within the scope of the function onNoServiceAvailable, it should automatically be marked for Garbage Collection when there are no more references to it. If your profiler is recognizing it's existence, then there is probably another reference to it somewhere in your code.

Inheritance with Flex mxml files - screenshot attached

In a Flex mobile app I have 5 Views, handling OAuth logins through 5 different social networks - including Google+ and Facebook. The Views are being selected through the menu shown below:
The filenames are FB.mxml, GG.mxml, MR.mxml, OK.mxml, VK.mxml and their source code looks very similar:
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
viewActivate="loadInfo(event)"
viewDeactivate="closeSWV(event)"
title="Facebook.com">
....
private function closeSWV(event:Event=null):void {
_busy.visible = _busy.includeInLayout = false;
_reload.visible = _reload.includeInLayout = true;
stage.removeEventListener(Event.RESIZE, resizeSWV);
if (! _swv)
return;
_swv.removeEventListener(Event.COMPLETE, extractAccessToken);
_swv.removeEventListener(LocationChangeEvent.LOCATION_CHANGE, extractAccessToken);
_swv.removeEventListener(IOErrorEvent.IO_ERROR, closeSWV);
_swv.removeEventListener(ErrorEvent.ERROR, closeSWV);
_swv.dispose();
_swv = null;
}
private function resizeSWV(event:Event=null):void {
if (! _swv)
return;
// align to the right-bottom corner
_swv.viewPort = new Rectangle(stage.stageWidth - Preferans.SCALE * width,
stage.stageHeight - Preferans.SCALE * height,
Preferans.SCALE * width,
Preferans.SCALE * height);
}
....
<s:VGroup>
<s:Label id="_first" fontWeight="bold" text="Your name:" />
<s:Label id="_gender" fontWeight="bold" text="Gender:" />
<s:Label id="_city" fontWeight="bold" text="City:" />
</s:VGroup>
<s:Button id="_play"
label="Play"
click="startGame(event)"
includeInLayout="false"
visible="false" />
</s:View>
My problem is: The 5 mxml files listed above have many similar methods and variables and UI elements and only few different methods and variables.
I've tried to introduce a "base class" for them all several times already and have always given up, because it is not straightforward for mxml files (versus pure AS3 classes).
Does anybody please have an idea, how to approach this?
You can define an abstract class that extends the UI component that you want to use in each row of the list. In your case, it will extend View.
package your.package{
public class SocialAccountView extends View{
// in this class you can add the generic methods
// that you want the view to have
}
}
After that, in the mxml file you can use the class you created as the main type instead of View
<your.package:SocialAccountView
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
viewActivate="loadInfo(event)"
viewDeactivate="closeSWV(event)"
title="Facebook.com">
</your.package:SocialAccountView>
With this you know that all the items in the list are of that type, and have the methods of the parent class. You can even override methods in each view.
Regarding the UI components, the maximum abstraction level (that I am aware of) you can have with them is to build an extra component and use it in all views. Something like...
Labels.mxml
<s:VGroup>
<s:Label id="_first" fontWeight="bold" text="Your name:" />
<s:Label id="_gender" fontWeight="bold" text="Gender:" />
<s:Label id="_city" fontWeight="bold" text="City:" />
</s:VGroup>
and then use it in each component like
<your.package:Labels
id="labelsComponent"/>
Hope this helps.

Flex: how to control Spark datagrid header-text alignment?

If I have 10 columns in a Spark datagrid, and some headers need to be left-justified, some headers right-justified, and some centered, what's the simplest way to accomplish this?
Assuming a custom headerRenderer is needed, are there any simple examples that can walk me through it?
Thanks in advance for any comments.
The simplest way I could find to solve this is to override the settings in the spark DefaultGridHeaderRenderer, as discussed in this link:
http://flexponential.com/2011/10/30/changing-fontweight-of-spark-datagrid-headers/
More specifically, I used the following custom headerRenderer, saved as file: myRightHeaderRenderer.mxml:
<?xml version="1.0" encoding="utf-8"?>
<s:DefaultGridHeaderRenderer 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:Declarations>
<s:Label id="labelDisplay"
verticalCenter="1" left="0" right="0" top="0" bottom="0"
verticalAlign="middle"
maxDisplayedLines="1"
textAlign="right"
fontWeight="bold"
showTruncationTip="true" />
</fx:Declarations>
</s:DefaultGridHeaderRenderer>
This custom header renderer right-justifies header text. To use it, simply add it to one or more columns of the Spark DataGrid as follows:
...
<fx:Array>
<s:GridColumn ... />
<s:GridColumn headerRenderer="myRightHeaderRenderer" ...>
<s:GridColumn ... />
...
</fx:Array>
...
I'm not sure how to do it, but I'm sure it can be made more flexible by parameterizing the textAlign attribute to be center, left, or right.
If you take a look at this blog post, there's a decent amount of source code available showing you how to do this.
However, I think that the blog's example is much more complex than you'll need. You will need a custom headerRenderer, as you feared, but your code should be pretty straightforward. I've only tested this lightly, so if you have any issues, let me know.
Custom Header Renderer
package
{
import spark.skins.spark.DefaultGridHeaderRenderer;
public class CustomGridHeader extends DefaultGridHeaderRenderer
{
public function CustomGridHeader()
{
super();
}
public function set headerTextAlign(value:String):void
{
labelDisplay.setStyle("textAlign",value);
labelDisplay.styleChanged("textAlign");
}
}
}
Variables Available to Your Columns...
[Bindable] private var leftFactory:ClassFactory = new ClassFactory(CustomGridHeader);
[Bindable] private var rightFactory:ClassFactory = new ClassFactory(CustomGridHeader);
[Bindable] private var centerFactory:ClassFactory = new ClassFactory(CustomGridHeader);
On initialize or preinitialize...
leftFactory.properties = {headerTextAlign: "left"};
rightFactory.properties = {headerTextAlign: "right"};
centerFactory.properties = {headerTextAlign: "center"};
For Each Column...
<s:GridColumn headerText="..." headerRenderer="{centerFactory}"/>