I'm really frustrated in this case.
While developing with Adobe Flex, I'm working on my first application - and use pretty much actionscript.
In my mxml application, I include as3 file via <mx:Script source="as/myas3file.as></mx:Script>.
In myas3file.as, I include (thru include "variables.as";) file variables.as, which contains following code:
var timer:Object = new Object();
timer.t = 60;
or (in other test case)
var timer:Object = {t:60, j:"80"};
timer.t = 80;
Neither case works! Even if I rewrite example code from official documentation, it throws an 1020 error. I'm banging my head to the table for last two hours and I can't figure out what I'm doing wrong.
Thank you
If the code is included from a <Script /> tag in an MXML application, then what you're defining is a member variable and you can't use statements. From the docs:
You use the <mx:Script> tag to insert
an ActionScript block in an MXML file.
ActionScript blocks can contain
ActionScript functions and variable
declarations used in MXML
applications.
...
Statements and expressions are allowed only if they are wrapped in a function. In addition, you cannot define new classes or interfaces in blocks. Instead, you must place new classes or interfaces in separate AS files and import them.
Instead, you can use an initializer as in your second example:
private var name:Object = { field: 80 };
or you can do the initialization in a function (constructor, initialize/creation complete event handler).
Related
For obvious reasons we want to start with TS instead of JS in our project.
The problem we occurred are the variables who are set in the MVC Views which are set by the Model of the given View.
E.g. tes.cshtml:
#model Testmodel
<script>
var test = {};
var test.myProp = #Model.Testproperty;
<script>
Now in my test.ts I got an error when I try to get the test-variable because my TypeScript file doesn't know it.
Do I have a architecture miss-conception here? Or is there a trick to do that?
To be honest we have around 100 variables set and / or created in RazorViews, most likely a lot of Ressource-Variables from our resx files we would need e.g. in a java-script alert!
You can create definitions file and put all your global declarations there. For example:
declare interface SampleInterface{
myProp:string;
myFunc(someParameter:string):void;
}
declare var test:SampleInterface;
declare var someFunc: () => number;
More info on writing declaration files here.
One way is to attach to Window all your variables or even all your resource variables and after that you can create something like a helper in typescript where you can parse Window.Variables and Window.ResxVariables for your need.
Server-side you will need two dictionaries Variables and ResxVariables which can be statics in your base controller.
Then you will need two methods that will facilitate adding variables to these dictionaries
Variables.Add("Timezone", "GMT+2");
And
ResxVariables.Add("ExitAlert", "Please stay more");
These two methods will be accessible in your controller actions and you will have the possibility to add model properties too.
Then you will need a HtmlHelper that will help you render those dictionaries as objects attached to Window.
You will need to also support clearing those dictionaries when you render a new page or depends on your need.
When i used something like this, we had two dictionaries GlobalVariables and PageVariables. Global wasn't cleared when we render a new page, but PageVariables was.
I want to draw something on an <mx:Image> I have in my .mxml file, but I want to keep my drawing implementation in a separate AS class.
How can I access my drawing AS class in my .mxml?
I think what your are asking is how to keep your actionscript files separate from the MXML files that contain your designs. The answer is simple:
Create your actionscript file. Include only methods in this file, and do not wrap the code in a package or class definition. The file should look like the following:
import mx.controls.Alert;
// ActionScript file
/**
*
* Created By jviers
* Created on Apr 14, 2011
*
*
*/
public function hello():Alert{
Alert.show("Hello World!");
}
Create your MXML file that contains your "Design" components. Create a Script element on this mxml file and set the source to the relative path of your ActionScript file. The MXML should look like this:
<?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[
protected function button1_clickHandler ( event : MouseEvent ) : void {
// TODO Auto-generated method stub
hello ();
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script source = "./scratch/MyFile.as" />
<s:Button label = "Show Alert" click = "button1_clickHandler(event)" />
</s:Application>
You'll notice that the ActionScript in the scratch.MyFile.as is executed when the application is run.
You can use this method to include your drawing logic in your application. The external ActionScript is treated as if it were the method definitions for the class generated by the MXML.
Let me caution you before everyone jumps all over me. This is NOT a best practice. There are specific use-cases in which to use this feature of Flex. Before I get to them let me explain why your notion of keeping "logic" separate from your "view" is inaccurate.
Flex MXML files are not view-only code. They are a declarative dialect that simplifies ActionScript class definitions. When a Flex Project is compiled using mxmlc or compc (those are the compiler programs for flex applications and component libraries, respectively), MXML files are pre-compiled into ActionScript class definitions. If you add the -keep-generated-actionscript directive to your compiler options in Flash/Flex Builder/Ant/command line compile command, the compiler will leave the generated classes that compose the ActionScript class derived from the declaritive MXML files in your project. Thus, an MXML file becomes a class.
Having ActionScript defined in a Script block in your MXML is NOT mixing "logic" with "presentation". Likewise, MXML does NOT define the presentation of your project. It simply is a declarative subset of the ActionScript language that makes it easier to define presentation classes. As proof, you can define ArrayCollections, Strings, and Vectors in MXML. Those classes are data containers and have absolutely nothing to do with presentation.
Now, the reason putting all your ActionScript in external files is not a good thing is that it makes maintaining your project a headache. Not only does someone have to look up your component defined in MXML, but now they have to hunt through the codebase to find the script named Logic.as relatively defined to your component.
The use-cases in which including the external ActionScript via Script.source are the following:
A group of predefined methods/properties are used in lots of components without change. Rather than copy-and-paste those methods into each component, you use the Script.source property to define the methods once and reference them throughout your application.
Similar, but different from use-case-1: You require a mix-in. Like an interface, a mix-in is a set of methods that must be defined for the component to work, and those methods must be reusable and define explicit input parameters and output parameters. Unlike an interface, those methods can be of any namespace type: protected, final, public, internal, mx_internal, etc., and can must function bodies, i.e. have code inside the {} function block. For an example of a "mix-in" think of an enumerable object, an object that has next(), previous(), reset(), and iterator(), methods. When you want to iterate over the object's properties, you call iterator(), which returns an iterator object that calls next() and previous() to fetch the next and previous property values from the object. You can mix this functionality into all kinds of objects and use them usefully. Also, your included functionality is encapsuled within the classes in which it is included. It works like an include directive in AS3.
Hope this helps both your perceptions of what "logic" and "presentation" are in Flex, and helps you solve your particular issue.
I think you have it backwards. If you include the .as file into the .mxml using the <mx:script> tag, you will be able to see the function defined therein.
To address the image, set it an id attribute. From that point, it becomes addressable as if it were defined using ActiveScript like
var image:Image = new Image()
It is no very obvious what relations are between MXML and AS classes you're talking about but the simplest way is create public method in MXML which returns Image. Something like this:
…
<mx:Script>
<![CDATA[
public function getImage():Image
{
return myImage;
}
]]>
</mx:Script>
<mx:Image id="myImage" />
…
So as far as you can refer to your MXML from AS you can call this method.
If you want to draw something in an image by using your own drawing class, i suggest you add it to the constructor of your drawing class, like so:
/*********************************************
* Variables
*********************************************/
private var _myImageIWantToDrawIn:Image;
/*********************************************
* Properties
*********************************************/
public function set image(value:Image):void
{
_myImageIWantToDrawIn = value;
}
public function get image():Image
{
return _myImageIWantToDrawIn;
}
/*********************************************
* Constructor
*********************************************/
public function myDrawingclass(imageYouWantToDrawIn:Image)
{
_myImageIWantToDrawIn = imageYouWantToDrawIn;
}
like this, you can always access the image from that class and draw in it if you want to. (You can also access the _myImageIWantToDrawIn.graphics if you want to draw programmaticaly). you can add the properties if you want to change the image in runtime. you can then simply say: myDrawingclass.image = imageYouWantToDrawIn;
edit: this previous answer was actually the opposite of what you are asking, but I think this will do just fine for what you would want to do. If you want to access your as-class, just make an instance of your class and add public methods to it instead of private ones.
I'm re-writing an MXML item renderer in pure AS. A problem I can't seem to get past is how to have each item renderer react to a change on a static property on the item renderer class. In the MXML version, I have the following binding set up on the item renderer:
instanceProperty={callInstanceFunction(ItemRenderer.staticProperty)}
What would be the equivalent way of setting this up in AS (using BindingUtils, I assume)?
UPDATE:
So I thought the following wasn't working, but it appears as if Flex is suppressing errors thrown in the instanceFunction, making it appear as if the binding itself is bad.
BindingUtils.bindSetter(instanceFunction, ItemRenderer, "staticProperty");
However, when instanceFunction is called, already initialized variables on the given instance are all null, which was the cause of the errors referenced above. Any ideas why this is?
You have 2 options that I am aware of:
Option 1
You can dig into the code that the flex compiler builds based on your MXML to see how it handles binding to static properties. There is a compiler directive called -keep-generated-actionscript that will cause generated files to stick around. Sleuthing through these can give you an idea what happens. This option will involve instantiating Binding objects and StaticPropertyWatcher objects.
Option 2
There is staticEventDispatcher object that gets added at build time to classes containing static variables see this post http://thecomcor.blogspot.com/2008/07/adobe-flex-undocumented-buildin.html. According to the post, this object only gets added based on the presence of static variables and not getter functions.
Example of Option 2
Say we have a class named MyClassContainingStaticVariable with a static variable named MyStaticVariable and another variable someobject.somearrayproperty that we want to get updated whenever MyStaticVariable changes.
Class(MyClassContainingStaticVariable).staticEventDispatcher.addEventListener(
PropertyChangeEvent.PROPERTY_CHANGE,
function(event:PropertyChangeEvent):void
{
if(event.property == "MyStaticVariable")
{
someobject.somearrayproperty = event.newValue as Array;
}
});
I think you need to respond to the "PropertyChanged" event.
If you're going to do that, use a singleton instead of static. I don't think it will work on a static. (If you have to do it that way at all, there are probably a couple ways you could reapproach this that would be better).
var instance:ItemRenderer = ItemRenderer.getInstance();
BindingUtils.bindProperty(this, "myProperty", instance, "theirProperty");
After fiddling with this for a while, I have concluded that this currently isn't possible in ActionScript, not even with bindSetter. It seems there are some MXML-only features of data bindings judging by the following excerpt from the Adobe docs (though isn't it all compiled to AS code anyways)?
You cannot include functions or array
elements in property chains in a data
binding expression defined by the
bindProperty() or bindSetter() method.
For more information on property
chains, see Working with bindable
property chains.
Source: http://livedocs.adobe.com/flex/3/html/help.html?content=databinding_7.html
You can create a HostProxy class to stand in for the funciton call. Sort of like a HostFunctionProxy class which extends from proxy, and has a getProperty("functionInvokeStringWithParameters") which will invoke the function remotely from the host, and dispatch a "change" event to trigger the binding in typical [Bindable("change")] Proxy class.
You than let the HostProxy class act as the host, and use the property to remotely trigger the function call. Of course, it'd be cooler to have some TypeHelperUtil to allow converting raw string values to serialized type values at runtime for method parameters (splitted by commas usually).
Example:
eg.
var standInHost:Object = new HostFunctionProxy(someModelClassWithMethod, "theMethodToCall(20,11)");
// With BindingUtils.....
// bind host: standInHost
// bind property: "theMethodToCall(20,11)"
Of course, you nee to create such a utlity to help support such functionality beyond the basic Flex prescription. It seems many of such (more advanced) Flex bindings are usually done at compile time, but now you have to create code to do this at runtime in a completely cross-platform Actionscript manner without relying on the Flex framework.
I'm working on an Flex application which uses many objects, e.g. LEDs, bulbs, gauges created in Flash. The objects internally consist of several small MovieClips and have their own logic inside. One of the initial requirements was that the objects have to be loaded at runtime, thus they were exported as SWF, not SWC. However, we ran into problem when we tried to duplicate loaded SWF. It turned out that MovieClip class doesn't have neither copying constructor nor method that would allow us to clone existing MovieClip. This way we'd end up loading an object every time from hdd, which involves a lot of overhead. Is it possible that language like ActionScript 3 doesn't have such a mechanism? Have we missed something out? If not, am I correct that the only solution is to use Flash Component Kit, make some custom components and include them as SWC at compile time?
After you load the MovieClip is it possible to use getDefinitionByName() as shown here?
http://livedocs.adobe.com/flex/3/langref/flash/utils/package.html#getDefinitionByName()
You are correct in that there is no built in way to duplicate a movieclip.
There are however work arounds. The esiest way as I see it is to give the movieclips classes.
You don't have to make the actual classes. Just write any name in the class field when setting up linkage on the top most movieclip that needs to be copied.
So a name for you LED movieclip, another name for the bulb etc.
The benifit is that now you have a class that you can initiate objects from.
No when you grap one of the movieclips you can duplicate it with the following method:
public function DuplicateDisplayObject(dO:DisplayObject):DisplayObject
{
if(dO == null)
return null;
var dOClass:Class = Object(dO).contructor;
return DisplayObject(new dOClass());
}
This assumes of cause that you can actually get a hold of one of the movieclips first. And mind you that it doesn't copy the state of the movieclip.
Another more importent note is that this only works if the you link the movieclips to classes. The classes doesn't have to exist (flash will create empty classes for you).
Other solutions could be:
Compiling against the classes without
including them (see the
"external-library-path" tag for the
flex compiler), and load the them at
runtime (from swf).
Compiling against the classes as a
RSL (Runtime Share Library) the swc
will be loaded at runtime.
Adobe has more info on how to do that, should be easy to find on their website.
A more exotic solution would be copy the bytecode of an object. Not sure if that would work with something on the displaylist, properly not.
About the solution using getDefinitionByName():
If I remember correctly you still need to give the movieclips fake classes, since getQualifiedClassName only returns MovieClip class. But I could be wrong.
Another solution:
private function duplicateImg(sourceLoaderInfo:LoaderInfo, target:Image):void
{
var ba:ByteArray = sourceLoaderInfo.bytes;
var dupCliploader:Loader = new Loader();
dupCliploader.contentLoaderInfo.addEventListener(
Event.COMPLETE, bytesLoaded);
dupCliploader.loadBytes(ba);
}
private function bytesLoaded(event:Event):void
{
var mc:MovieClip = event.currentTarget.content as MovieClip;
_img.source = mc;
_img.width = mc.width;
_img.height = mc.height+5;
}
MXML lets you do some really quite powerful data binding such as:
<mx:Button id="myBtn" label="Buy an {itemName}" visible="{itemName!=null}"/>
I've found that the BindingUtils class can bind values to simple properties, but neither of the bindings above do this. Is it possible to do the same in AS3 code, or is Flex silently generating many lines of code from my MXML?
Can anyone duplicate the above in pure AS3, starting from:
var myBtn:Button = new Button();
myBtn.id="myBtn";
???
The way to do it is to use bindSetter. That is also how it is done behind the scenes when the MXML in your example is transformed to ActionScript before being compiled.
// assuming the itemName property is defined on this:
BindingUtils.bindSetter(itemNameChanged, this, ["itemName"]);
// ...
private function itemNameChanged( newValue : String ) : void {
myBtn.label = newValue;
myBtn.visible = newValue != null;
}
...except that the code generated by the MXML to ActionScript conversion is longer as it has to be more general. In this example it would likely have generated two functions, one for each binding expression.
You can also view the auto-generated code that flex makes when it compiles your mxml file, by adding a -keep argument to your compiler settings. You can find your settings by selecting your projects properties and looking at the "Flex Compiler" option, then under "Additional compiler arguments:" add "-keep" to what is already there.
Once done Flex will create a "generated" directory in your source folder and inside you'll find all teh temporary as files that were used during compilation.
I believe flex generates a small anonymous function to deal with this.
You could do similar using a ChangeWatcher. You could probably even make a new anonymous function in the changewatcher call.