Flex: application is confused when passing variables to custom component - actionscript-3

I'm new to Flex and I'm missing something very basic about architecting a Flex application -- I've implemented a custom component MyReportGrid and extended GridColumn with MyColumn. I've tried to outline the application code below.
The interesting thing to notice is that class OfficeItems is used by class MyItems, and the MyColumn (which extends GridColumn) includes a customPath variable that is used to access variables pen, pencil, and stapler inside class OfficeItems.
I believe that is the reason why manually sorting (by clicking on the columns in the datagrid) only works for columns corresponding to zipCode and stateCode and NOT pen, pencil, and stapler.
Also, when I try to use a simple labelFunction for zipCode or stateCode it always works fine, but implementing a labelFunction for pen, pencil, or stapler never works. By "never works" I mean that the labelFunction is called correctly, and it performs it's required task in that the labelFunction receives the correct object and actually returns the correct formatted String, but this returned value is never displayed in the datagrid (I'm assuming the customPath variable confuses the labelFunction as to which variable the returned String maps to).
I think these are both the same issue in that the customPath aspect of the MyColumn confuses the application. Any idea how to fix the sorting and/or labelFunction? Thanks in advance for your patience in reading this (long) posting.
The classes are:
package com.supportClasses
{
public class OfficeItems {
public var pen:*;
public var pencil:*;
public var stapler:*;
}
}
and
package com.models
{
import com.supportClasses.OfficeItems;
[Bindable]
public class MyItems extends Model {
public function myItems() {
super();
}
public var office:OfficeItems;
public var zipCode:int;
public var stateCode:String;
}
}
The data grid looks like:
...
<components:MyReportGrid id="myGrid" dataProvider="{_myData}"...>
<components:columns>
<fx:Array>
<supportClasses:MyColumn customPath="office" dataField="pen"... />
<supportClasses:MyColumn customPath="office" dataField="pencil"... />
<supportClasses:MyColumn customPath="office" dataField="stapler"... />
<supportClasses:MyColumn dataField="zipCode"... />
<supportClasses:MyColumn dataField="stateCode"... />
...
where _myData has a class of MyItems (note: the customPath feature is ignored by MyColumn when not present here, such as for zipCode and stateCode). MyColumn is:
package com.components.supportClasses {
import spark.components.gridClasses.GridColumn;
public class MyColumn extends GridColumn
{
public var customPath:String="";
...
public function MyColumn(headerText:String="header" customPath:String="", dataField:String="data", ...) {
this.headerText=headerText;
this.customPath=customPath;
this.dataField=dataField;
...
}
}
}
and MyReportGrid is:
package com.models {
<?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">
import com.components.myClasses.MyColumn;
import com.itemRenderers.myItemRenderer;
import mx.collections.ArrayCollection;
import mx.collections.ArrayList;
import mx.collections.ListCollectionView;
import spark.components.gridClasses.GridColumn;
...
<s:DataGrid width="100%" ... />
</s:Group>
}
the labelFunction is:
private function redFormat(item:Object, column:MyColumn):String {
var formatResult:String = "red "+item.office.pen;
return formatResult; // returns "red Bic15938" (for example)
}
as called from:
<supportClasses:MyColumn customPath="office" dataField="pen" labelFunction="redFormat"... />

This is just a guess, but could it be something like adding a "toString" function to the OfficeItems class? (I would be using comments, but still working on getting reputation.)

Related

Alter ResourceManager to split values by semicolon, not comma

As the title says, is there a way to alter the ResourceManager's getStringArray() in a way that it splits the resources by semicolon, not comma?
The actual method can be found in the ResourceManagerImpl class, which can be found in in the package mx.resources.
Overriding that method would be fine, but ideally I'd like to write my own getStringArray with a variable separator, however, there seems to be no way of extending either the ResourceManager or ResourceManagerImpl class to somehow add that method.
Anyone got a clue what to do here?
The problem is not that you can't extend ResourceManagerImpl since it's not final, but rather that you have to be able to register your implementation with the application instead of the default one. And doing this is a bit tricky.
So first create your implementation:
public class MyResourceManager extends ResourceManagerImpl {
private static var instance:IResourceManager;
static public function getInstance():IResourceManager
{
if (!instance) instance = new MyResourceManager();
return instance;
}
override public function getStringArray(bundleName:String,
resourceName:String,
locale:String = null):Array {
//do your stuff
}
}
So we've overriden the getStringArray method. Notice that we've done the same for getInstance, because we want it to return a new instance of MyResourceManager instead of ResourceManagerImpl (we don't have to mark override because it's a static method). Also, you may have to write some import statements manually, because some of the classes you're using are marked as 'excluded'.
Now we have to tell Flex to use MyResourceManager instead of ResourceManagerImpl. We can do this with the following code:
import mx.core.Singleton;
Singleton.registerClass("mx.resources::IResourceManager", MyResourceManager);
The problem is that we have to do this before Flex registers ResourceManagerImpl, because you can't override it once it's registered. For this we need to create a custom preloader in which we do the registering (sadly, the Application's 'preinitialize' phase is not early enough).
public class RegisteringPreloader extends DownloadProgressBar {
override public function initialize():void {
super.initialize();
Singleton.registerClass("mx.resources::IResourceManager",
MyResourceManager);
}
}
Now assign the custom preloader to the application and we're done:
<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"
preloader="RegisteringPreloader" >
For further info I refer you to a fairly similar, but somewhat more elaborate answer that I wrote for a different question: Is there a way to listen for events on the pop up manager class?
Just for the record: if you want to provide your localization with array of strings containing commas, it is way easier to use getObject method of IResourceManager.
In your properties file:
my.beloved.strings: ["That's it, string one", "Okay, string two"]
In your code:
var strings:Array = _resourceManager.getObject(_bundleId, 'my.beloved.strings') as Array;
var stringOne:String = strings[0];
You don't have to override anything this way.

Flex : Communicate between the skin and the data model?

How to send to the skin some value which have changed?
There are two approaches to this: one uses binding and is easier, the other is more complex but better for performance.
Using binding
Suppose your view class looks like this:
public class MyClass extends SkinnableComponent {
[Bindable] public var myValue:String;
}
then you can bind to that value in your skin like this:
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Metadata>
[HostComponent("MyClass")]
</fx:Metadata>
<s:Label id="myLabel" text="{hostComponent.myValue}" />
</s:Skin>
Overriding commitProperties
Assume the same skin without the binding, then you can set the label's text property by using a skinpart and overriding commitProperties in the host component. The skinpart's name must be exactly the same as the id of the component in the skin (in this case 'myLabel').
public class MyClass extends SkinnableComponent {
[SkinPart(required="true")]
public var myLabel:Label;
public var myValue:String;
override protected function commitProperties():void {
if (myLabel) myLabel.text = myValue;
super.commitProperties();
}
}
Of course you would have to call invalidateProperties() whenever you want to apply the new value (for instance in a setter function for 'myLabel'). Also notice that 'myLabel' no longer needs to be bindable, unless you would want to be able to bind on it externally.
edit: which approach to choose?
I have just answered a question that is closely related to this one in which I elaborate on the pro's and cons of each approach in different situations. You can find it here: Flex: Additional label in ButtonBarButton

Action script3 trace in flex builder

this is the code, i am using flex builder 4.5,
<?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[
public var ss:Array = ["a", "b", "c"];
trace(ss[0]);
public var str:String = "Good Luck";
trace(str);
]]>
</fx:Script>
</s:Application>
i get red cross next to trace statment and fault is
"1120:Access of defined property ss"
i have tried the commented line as well but no luck. i have tried with 3.5, 4.1 and 4.5 sdk.
Am i missing something? please guide!!
(i tried googling it but nothing came up )
thanks in advance.
(updated the code)
public var ss:String is a field declaration and trace(ss) is an action in code execution flow. Place trace(ss) in an appropriate scope (in a function aka method) and it will be compiled and executed without any problem.
I think you are getting confused between Class member properties and local variables. Inside a method, you can only declare local variables, for example:
public function debugString() : void {
// declare a local property, only this, 'debugString' function can acess
// or modify this property - it is deleted when this function finishes.
var myString : String = "Hello World";
trace(myString);
}
However, it would appear that you were trying to define Class member properties instead (because you were declaring the visibility of the property (ie: public)).
public class HelloWorld {
// Define a Class member property; all functions in this Class will be
// able to access, and modify it. This property will live for as long as the
// Class is still referenced.
public var myString : String = "Hello World";
public function debugString() : void {
// notice how we did not declare the 'myString' variable inside
// this function.
trace(myString);
}
}
Note that you can only access member properties once a Class has been constructed; so the earliest you can (sensibly) access them is in your Constructor, for example:
class HelloWorld {
public var myString : String = "Hello World";
// This will not work, because you can only access static properties
// outside of a function body. This makes sense because a member property
// belongs to each instance of a given Class, and you have not constructed
// that instance yet.
trace(myString);
// This is the Class Constructor, it will be called automatically when a
// new instance of the HelloWorld class is created.
public function HelloWorld() {
trace(myString);
}
}
What you might be trying to do is make use of a static property; these differ from Class member properties as they are Globally shared amongst all instances of a given class. By convention, static properties are defined in CAPS:
public class HelloWorld {
// Here we define a static property; this is accessible straight away and you
// don't even need to create a new instance of the host class in order to
// access it, for example, you can call HelloWorld.MY_STRING from anywhere in your
// application's codebase - ie: trace(HelloWorld.MY_STRING)
public static var MY_STRING : String = "Hello World";
}

Can't use static const as param in function call within binding tags in Flex 3

I'm having a problem in flex 3 where if a static const I have defined is used as the parameter to a function call within binding tags I get a "1120: Access of undefined property NodePropertyMatrix". _propMtx is a ArrayCollection.
<mx:HBox visible="{_propMtx.getItemAt(NodePropertyMatrix.srcParent)}">
Above code throws the error, but the following code does not
<mx:HBox visible="{NodePropertyMatrix.srcParent}">
NodePropertyMatrix is an AS class as follows:
package model.constants
{
import mx.collections.ArrayCollection;
public class NodePropertyMatrix
{
public static const srcParent:Number = 0;
}
}
Anyone know what is wrong here?
Found the problem.
In the mxml file where I was importing the NodePropertyMatrix is was doing this:
import Constants.*;
Instead of this:
import Constants.NodePropertyMatrix;
For some reason it doesn't work in this instance without explicity importing that class. Wildcard didn't do the trick....not sure why, but ignorance is bliss.

Action Script - how to access label component defined in mxml file within action script class method?

I have a label component in a mxml file like below
<mx:Label x="700" y="409" text="Label" id="lble" width="131" height="41"/>
if i want to access it and change its text content within a method defined in action script class that i have written, how to do it?
lble.text="test";
To access the label, you have to import the Label component before the class definition, so it can be accessed:
import mx.controls.Label;
Then, declare the reference to the label in your class body:
public var lble:Label;
And, finally, you can address the label to manipulate it:
lble.text = "Hello world!";
The ID attribute makes it a private variable within the class or component, so
lble.text = "test";
is just fine.
You are talking about doing this within the same component or class, right? If not you should bind the value to a variable and use getters and setters, like so
[Bindable]
private var _labelText:String;
public function get labelText() : String {
return _labelText;
}
public function set labelText(value:String) : void {
_labelText = value;
}
and then
<mx:Label text="{_labelText}"/>