AddChild with Dynamic DispalyObject in Flex - apache-flex

I am pretty sure that this is totally what i need, however I can not get it to work for some reason. What i would like to do is call an arbitrary component that extends Canvas. Since there may be a variety of components named TestCanvasA, TestCanvasC, TestCanvasC which i won't know till run-time I figured this would be the way to go about it. Here is what i have.
<mx:Script>
<![CDATA[
import component.TestCanvas;
import mx.containers.Canvas;
import flash.display.Sprite;
import flash.utils.getDefinitionByName;
private function init(evt:Event):void{
var Type:String="TestCanvas";
var controlClass:Class = getDefinitionByName(Type) as Class;
this.addChild(new controlClass() as Canvas);
}
]]>
</mx:Script>
Any ideas would be awesome!

Give it the fully qualified class name:
var type:String="component.TestCanvas";
var controlClass:Class = getDefinitionByName(Type) as Class;
Also a mere import statement need not include the definition of the class in the compiled SWF unless there are references to the class inside the application. Just declare (need not initialize) a variable of that type somewhere in the SWF to make sure that the definition is indeed included.
var dummy:TestCanvas;

Related

Autocompletion in FlashDevelop doesn't work in included files

Why doesn't autocompletion work for function's local variables in included *.as files? For example:
Main.mxml:
<fx:Script>
<![CDATA[
include "code.as"; // or <fx:Script source="code.as"/>, doesn't matter
]]>
</fx:Script>
code.as:
import mx.controls.Button;
var foo:Button = new Button();
foo. <---- autocompletion is working here
function myFunc() {
var bar:Button = new Button();
bar. <----- doesn't work
}
Autocompletion will only work if a code class was imported, or if a class extended an .as class. Has to be a Class. When you use 'include code.as', code.as is not a class, its basically just a collection of variables, imports and functions, so autocomplete cannot access it like a class.
The code-behind pattern is similar to what your doing (seperating logic from the mxml), and allows for atuocompletion. To use it:
Create an Actionscript class that
extends an MXML control that you
want to use e.g. HBox or UIComponent
Put all of you logic within this
Actionscript class.
Then create an MXML class that
extends the Actionscript class.
Code completion will work in your new custom MXML class for accessing public/protected variables and functions.

Why is my object reference null when trying to reference an mx:Canvas from ActionScript?

this is a follow up question from this one, I don't want to keep going in the comments and preventing people from getting hard-earned reputation... :)
In my Cairngorm command class, to get it to compile I needed to tell it what myCanvas was, so I used this line:
var myCanvas : MyCanvas = new MyCanvas;
I'm guessing that's wrong, though, because although it compiles, if I try to do something like this:
if (myCanvas.subObject.value == 0) { ... }
it'll throw this error:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at com.foo.bar.command::MyCommand/execute()
as if the subObject doesn't exist. It looks like I might be getting a new instance of MyCanvas, not the instance I want from the main.mxml with an id of myCanvas. Am I right? How do I fix this?
Edit (10:59pm GMT+1): Okay, so it looks like I've been way too vague here. Here's my main.mxml:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:control="com.foo.bar.control.*"
xmlns:business="com.foo.bar.business.*"
xmlns:view="com.foo.bar.view.*"
applicationComplete="com.foo.bar.util.StartupUtil.init()"
horizontalScrollPolicy="off"
verticalScrollPolicy="off"
borderThickness="0"
paddingBottom="0"
paddingLeft="0"
paddingTop="0"
paddingRight="0"
>
<mx:Script>
<![CDATA[
import com.foo.bar.model.PlayerModelLocator;
[Bindable]
private var model : PlayerModelLocator = PlayerModelLocator.getInstance();
]]>
</mx:Script>
<!-- ========================================================================== -->
<!-- the ServiceLocator where we specify the remote services -->
<business:Services id="services" />
<!-- the FrontController, containing Commands specific to this application -->
<control:PlayerController id="controller" />
<!-- ========================================================================== -->
<mx:Style source="assets/main.css" />
<view:MyCanvas id="myCanvas" />
</mx:Application>
And here's my com/foo/bar/command/MyCommand.as:
package com.foo.bar.command {
/* add to controller
addCommand( MyEvent.EVENT_CHANGE_VOLUME, ChangeVolumeCommand );
*/
import flash.net.SharedObject;
import com.adobe.cairngorm.control.CairngormEvent;
import com.adobe.cairngorm.commands.ICommand;
import com.foo.bar.model.PlayerModelLocator;
import com.foo.bar.event.MyEvent;
import com.foo.bar.view.*;
public class ChangeVolumeCommand implements ICommand {
public function execute(event:CairngormEvent):void {
var model : PlayerModelLocator = PlayerModelLocator.getInstance();
var myEvent : MyEvent = MyEvent(event);
var myCanvas : MyCanvas = new MyCanvas();
var so:SharedObject = SharedObject.getLocal("fixie.video");
if (myCanvas.subObject.value == 0) {
trace("subobject value is 0");
}
}
}
}
Basically, I want to get a handle on the object with ID myCanvas in main.mxml using the myCanvas object in MyCommand.as
Could be a couple of things. First, you need parentheses on your class name after the "new" statement: new MyCanvas(); Second, you may be trying to access your sub component before the component lifecycle is ready for you to do so. (It's hard to tell from the code you posted since there isn't enough context.)
What is the scope of your myCanvas variable? Is it inside a method somewhere? You will need to make it public or give it getter/setter to be able to access it.
You may also be trying to reference it before it has been added to its parent, using the addChild() method.
There really isn't enough code in your examples to determine the problem, but these things should give you somewhere to start looking.
1 way is to add eventListener when your myCanvas will be ready after CreationComplete and to do all your stuff
and the second is:
define your subObject as in myCanvas class so you'll be able to access it on Init Stage of your component.
regards
Eugene
p.s. all of the time everybody want to get answer without well formed sample of their problem, its terrible!!

Flex error 1120 (Access of undefined property XXX) when using constants in MXML

Again pulling my hair out due to some Flex/AS3 weirdness. The following code does not compile due to error 1120 - Access of undefined property AbstractWizardModel
<mx:HBox id="cntr_buttons" width="100%" horizontalAlign="right">
<mx:Button label="{model.getButtonLabel(AbstractWizardModel.GO_BACK)}" />
</mx:HBox>
The constant is defined (in AbstractWizardModel) as:
[Bindable]
public class AbstractWizardModel extends EventDispatcher
{
public static const GO_BACK : String = "goBack";
...
}
Replacing 'AbstractWizardModel.GO_BACK' with '"goBack"' does the trick, but what was the problem?
Thanks!
PS: Of course I am importing the AbstractWizardModel in the MXML code
The error is about the class AbstractWizardModel, not about the constant GO_BACK. You need to have an import statement for the class inside the mxml file:
<mx:Script>
<![CDATA[
import the.package.AbstractWizardModel;
]]>
</mx:Script>
before you can use the class.
EDIT: replace "the.package." with whatever package the class is in.
Oh man this is so weird..
I found kind of a solution, thanks to all comments, which helped me to get on the right track, but still think this is a bug in Flex.
First of all I have to add that (in my code) the MXML and AbstractWizardModel class are in the same package.
The 'getButtonLabel()' function that I am calling is declared as
[Bindable(event="getButtonLabelChanged")]
public function getButtonLabel (buttonId:String) : String
{
..
}
If I remove that [Bindable..] annotation, the code compiles.
If I leave it there, I have to add an import for class AbstractWizardModel, although it is in the same package. Anyway, that fixes the problem, too.
However :) FB4 removes that import everytime it organizes imports, so that user comment was helpful too.
Happy to hear your thoughts!

Access to elements defined in MXML from External AS

I have a MXML with a form, and inside it, two TextInputs. I hate having any piece of code inside the MXML file (I come from a JavaScript formation) so I use a
mx:Script source="external.as"
tag to include any code used in any MXML file. The problem is that if I have this code on the external.as file:
private function populateFromForm():void{
var vo:ValidObject= new ValidObject();
vo.market = marketInput.text;
vo.segment = segmentInput.text;
vo.priceLow = priceLowInput.text;
vo.priceHigh = priceHighInput.text;
}
Where marketInput, segmentInput, priceLowInput and priceHighInput are TextInputs defined in the MXML file. When I try to complile I get a 1120: Access to undefined property XXXXX
I have tried adding this lines prior to the function:
public var marketInput:TextInput;
public var segmentInput:TextInput;
public var priceLowInput:TextInput;
public var priceHighInput:TextInput;
But instead I get a 1151:A conflict exists with definition XXXX in namespace internal which makes perfect sense.
Is there a way to do this without having to pass all the input references to the function as parameters of it?
You need to create a reference to an instance of the TextInputs' parent container, and then use that reference to accsess the TextInputs and their properties. I think we need some clarification on your file structure. How are you creating the instance of the parent container? I'm thinking this is what you need to do:
MyForm.mxml:
<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:TextInput id="marketInput" />
<mx:TextInput id="segmentInput" />
<mx:TextInput id="priceLowInput" />
<mx:TextInput id="priceHighInput" />
</mx:VBox>
SaveVOContainer.as:
package
{
public class SaveVoContainer extends Container
{
private var myForm:MyForm = new MyForm();
public function SaveVOContainer
{
this.addChild(myForm);
}
private function populateFromForm():void{
var vo:ValidObject= new ValidObject();
vo.market = myForm.marketInput.text;
vo.segment = myForm.segmentInput.text;
vo.priceLow = myForm.priceLowInput.text;
vo.priceHigh = myForm.priceHighInput.text;
}
}
}
Doing a "code-behind" is painful in Flex. There is no concept of partial classes or the flexibility of prototypal inheritance as in Javascript. Google for "code-behind in flex" for many resources.
I think it's better you get used to the idea of embedding code in mxml. Use script tags avoiding inline code as much as possible. If you have to write a lot of code within MXML, perhaps you may want to re-factor the code into multiple custom components. Bonus points if they are reusable.
The canonical way to do code-behind in Flex is via inheritance. Here's a good explanation from the docs: http://learn.adobe.com/wiki/display/Flex/Code+Behind. In a nutshell:
Declare an ActionScript class to use as your base class.
Set the base class as the root container in your MXML file.
For any controls declared in your MXML file, you have to redeclare them as public members of the base class using the exact same name (exactly as you are doing above for your script block with source tag, only it works :-)
So, your ActionScript file:
package mypackage
{
import mx.controls.TextInput;
public class myClass extends WindowedApplication
{
public var marketInput:TextInput;
private function populateFromForm():void{
/* As above */
}
}
}
And the corresponding MXML file:
<?xml version="1.0" encoding="utf-8"?>
<custom:myClass xmlns:custom="mypackage.*"
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<mx:TextInput id="marketInput"/>
</custom:myClass>
Et cetera for your other TextInput controls. And now your populateFromForm function should work.
It is kind of heinous to have to redeclare the same entities twice, but it's not quite the bag of hurt the earlier respondent made it out to be (although it's possible this changed in Flex 4 to make it less painful than it was).
import this in .AS:
import mx.core.Application;
in the .AS use this:
mx.core.Application.application.component.property = value;
mx.core.Application.application.myText.text = 'test';
do you have a script tag in your mxml file that points to your ActionScript file?
<mx:Script source='includes/foo.as' />

Possible to use Flex Framework/Components without using MXML?

Is it possible to use the Flex Framework and Components, without using MXML? I know ActionScript pretty decently, and don't feel like messing around with some new XML language just to get some simple UI in there. Can anyone provide an example consisting of an .as file which can be compiled (ideally via FlashDevelop, though just telling how to do it with the Flex SDK is ok too) and uses the Flex Framework? For example, just showing a Flex button that pops open an Alert would be perfect.
If it's not possible, can someone provide a minimal MXML file which will bootstrap a custom AS class which then has access to the Flex SDK?
I did a simple bootstrap similar to Borek (see below). I would love to get rid of the mxml file, but if I don't have it, I don't get any of the standard themes that come with Flex (haloclassic.swc, etc). Does anybody know how to do what Theo suggests and still have the standard themes applied?
Here's my simplified bootstrapping method:
main.mxml
<?xml version="1.0" encoding="utf-8"?>
<custom:ApplicationClass xmlns:custom="components.*"/>
ApplicationClass.as
package components {
import mx.core.Application;
import mx.events.FlexEvent;
import flash.events.MouseEvent;
import mx.controls.Alert;
import mx.controls.Button;
public class ApplicationClass extends Application {
public function ApplicationClass () {
addEventListener (FlexEvent.CREATION_COMPLETE, handleComplete);
}
private function handleComplete( event : FlexEvent ) : void {
var button : Button = new Button();
button.label = "My favorite button";
button.styleName="halo"
button.addEventListener(MouseEvent.CLICK, handleClick);
addChild( button );
}
private function handleClick(e:MouseEvent):void {
Alert.show("You clicked on the button!", "Clickity");
}
}
}
Here are the necessary updates to use it with Flex 4:
main.mxml
<?xml version="1.0" encoding="utf-8"?>
<local:MyApplication xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:local="components.*" />
MyApplication.as
package components {
import flash.events.MouseEvent;
import mx.controls.Alert;
import mx.events.FlexEvent;
import spark.components.Application;
import spark.components.Button;
public class MyApplication extends Application {
public function MyApplication() {
addEventListener(FlexEvent.CREATION_COMPLETE, creationHandler);
}
private function creationHandler(e:FlexEvent):void {
var button : Button = new Button();
button.label = "My favorite button";
button.styleName="halo"
button.addEventListener(MouseEvent.CLICK, handleClick);
addElement( button );
}
private function handleClick(e:MouseEvent):void {
Alert.show("You clicked it!", "Clickity!");
}
}
}
This is a very simple app that does only the basic bootstrapping in MXML. This is the MXML:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="onCreationComplete()">
<mx:Script source="Script.as" />
</mx:Application>
This is the Script.as:
import mx.controls.Button;
import flash.events.MouseEvent;
import mx.controls.Alert;
import mx.core.Application;
private function onCreationComplete() : void {
var button : Button = new Button();
button.label = "Click me";
button.addEventListener(MouseEvent.CLICK, function(e : MouseEvent) : void {
Alert.show("Clicked");
});
Application.application.addChild(button);
}
NOTE: The below answer will not actually work unless you initialize the Flex library first. There is a lot of code involved to do that. See the comments below, or other answers for more details.
The main class doesn't even have to be in MXML, just create a class that inherits from mx.core.Application (which is what an MXML class with a <mx:Application> root node is compiled as anyway):
package {
import mx.core.Application;
public class MyFancyApplication extends Application {
// do whatever you want here
}
}
Also, any ActionScript code compiled with the mxmlc compiler -- or even the Flash CS3 authoring tool -- can use the Flex classes, it's just a matter of making them available in the classpath (refering to the framework SWC when using mxmlc or pointing to a folder containing the source when using either). Unless the document class inherits from mx.core.Application you might run in to some trouble, though, since some things in the framework assume that this is the case.
Yes, you just need to include the flex swc in your classpath. You can find flex.swc in the flex sdk in frameoworks/lib/flex.swc
edit: One more thing: if you're using Flex Builder you can simply create a new ActionScript project, which will essentially do the same as above.

Resources