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.
Related
I have an mxml page that has this tag:
<fx:Declarations>
<mx:StringValidator id = "validator"
source = "{myTextInput}"
property = "text"
required = "true"
maxLength = "128"/>
<fx:Declarations>
I want to do the same in another page but build and add the validator dynamically using action script. I have this code for building the validator:
var lengthTextValidator:StringValidator = new StringValidator();
lengthTextValidator.source = fieldTextInput;
lengthTextValidator.property = "text";
lengthTextValidator.required = true;
How can I finish the work and add the validator to the page? Thanks!
To add a UIComponent as a child of another UIComponent you can use addChild():
myComponent.addChild(myOtherUIComponent);
However, a validator is not a UIComponent or DisplayObject. It does not get added as a child to a page. If you are just replacing the fx:Declaration piece of an MXML file with an ActionScript piece that does the same thing, then you don't have to do much more.
I would make the lengthTextValidator a public, or protected, instance variable on the component:
public var lengthTextValidator:StringValidator = new StringValidator();
That means the variable will be use within the component. Your original syntax without the public or private will either make a method specific variable that won't be accessible when the method is done executing or will put the variable in the internal namespace.
The rest of your code must go in a method. For an ActionScript class; you can put it in a constructor. Or for a MXML class you can put it in an initialize or creationComplete event handler.
lengthTextValidator.source = fieldTextInput;
lengthTextValidator.property = "text";
lengthTextValidator.required = true;
If you are putting the validator code in a separate class; then you'll have to import the class and create an instance of it:
import myPackage.MyClass;
public var myClass :MyClass = new MyClass();
Then you can access the validator by accessing the public variable on the component:
myClass.lengthTextValidator;
Finally; if you just want to move that snippet into an ActionScript file that is not a class; you can use the include directoive inside a fx:Script block:
<fx:Script><[[
include "myASFile.as"
]]></fx:Script>
The last approach is unorthodox and not usually recommended.
I have a protected function defined in a script block of a component defined in mxml like so:
<s:VGroup 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="onCreationComplete()">
<fx:Script>
<![CDATA[
protected function onCreationComplete():void {
}
...
Is it possible to override the function in an instance of the component like so:
<gen:CreateObjectFormSubmit id="formSubmit">
<fx:Script>
<![CDATA[
override protected function onCreationComplete():void {
form=form1;
}
]]>
</fx:Script>
Sure, you can. MXML component is a class , so if you create component B based on component A (B inherits from A), then you can override methods of A in B.
Just be careful with where and how you are declaring your super class. From the syntax provided above, it appears you might be trying to declare a <component> tag in your mxml class, in which if this is the case - the compiler treats this as a separate child object and not an actual extension.
For one, root level tags cannot declare an id (but components can - and this becomes the Class name), and you would most likely need to explicitly declare all your xml namespaces.
In order for it to be a true extension, your first <VGroup> Class would need to be named CreateObjectFormSubmit, this becomes the root tag of your extending class. There is one gotcha though, if you extend from an mxml class you cannot declare any additional children (in mxml notation because of layout rules).
If as you say an instance of your class, then no you wouldn't be able to override it, since the function scope of the <Script> tag would still reside within the root level. This is also sometimes referred to as the 'outerDocument' when declaring <component> tags.
The above wouldn't be any different doing it in regular AS like the following:
class SomethingCool extends UIComponent {
...
public function addButtons():void
{
var btn:Button = new Button();
btn.id = 'formSubmit';
//can't declare an override of Button here
}
}
to override any function, a function which u want to override should be available in parent class of ur current class.
public class A {
public function methodtooverride():void{
trace('in class A');
}
}
public class B extends A {
override public function methodtooverride():void{
trace('in class B');
}
}
I have several mxml components in an app, all of which need the same variable called genericX. I've included that variable in the main mxml and made it public
[Bindable] public var genericX:Number = 102;
but I still can't access it from other mxml components. If I try to do this for example, it doesn't recognize the variable.
<s:Button x="{genericX}" label="Click" />
There's also a filthy solution that works but isn't nice. You can create a static variable against the application class. For example:
[Bindable] public static var genericX : Object
You can access that from anywhere like this:
MyApplicationName.genericX
It ain't pretty, but it does work :)
simon
You cannot access in this way. There is something called Events in Flex and you need to pass this variable in a MXML file to another using eventDispatcher.
For example
[Bindable] public var genericX:Number = 102;
private function init():void {
var evt:NewCustomEvent = new CustomEvent(CustomEvent.SENDDATA);
evt.genericaValue = genericX
dispatchEvent(evt);
}
Now you need to get into the MXML component where you want to recieve this Event and using addEventListner() to recieve this event and the corresponding variable.
Then finally Inject it into your button.
You should be able to access any global variables with:
Flex 3:
var app:Application = mx.core.Application.application as Application;
Flex 4(looks like what you're using):
var app:Object = FlexGlobals.topLevelApplication;
And then:
<s:Button x="{app.genericX}" label="Click" />
x="{parentApplication.genericX}"
Here is an example for sharing variables between MXML components by declaring them public in the main application.
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' />
I'm currently maintaining some flex code and noticed very many functions which are declared like:
private function exampleFunc():void {
....
}
These functions are in the global scope, and aren't part of any specific class, so it's a bit unclear to me what effect declaring them as private would have. What restrictions does the "private" qualifier have for functions like this?
The actionscript functions that are included in your mxmlc code will we available as a part of your mxmlc component, which behind the scenes is compiled into a class. Therefore marking them as private makes them inaccessible.
Here is an example to make that clear, say you have the following component, we'll call it FooBox:
<!-- FooBox.mxml -->
<mx:Box xmlns:mx="http://www.macromedia.com/2003/mxml">
<mx:Script><![CDATA[
private function foo():void {
lbl.text = "foo";
}
public function bar():void {
lbl.text = "bar";
}
]]></mx:Sctipt>
<mx:Label id="lbl">
</mx:Box>
I can now add FooBox to my application, and use it's functions:
<mx:Application
xmlns:mx="http://www.macromedia.com/2003/mxml"
xmlns:cc="controls.*"
>
<mx:Script><![CDATA[
private function init():void {
fbox.foo(); // opps, this function is unaccessible.
fbox.bar(); // this is ok...
}
]]></mx:Sctipt>
<cc:FooBox id="fbox" />
</mx:Application>
If the actionscript functions are included in your Main Application file, the I think you can call the functions from an child control through the Application.application object, something like:
Application.application.bar();
if the bar function was placed in the main mxmlc code.
What do you mean by global scope? Are these functions declared in the main MXML file?
In general, private means that functions can only be called from within the class that declares them.
But, when you put it in a actionscript file .as is it still compliled into a class ?
Because asdoc doesn't like it.