I used to work on AS2 and make games, and now I wanna learn AS3 and have all its nice features (using Flash CS IDE). Now I m trying to rewrite a function to discard it.
function something():void{
//do something
}
function something():void{}
like this. please help or just give some alternatives, thanks.
What you're trying to do is very illogical - a function should be defined once and exist always. Not only that, but it should definitely always behave the same way, especially considering AS3 does not support overloading.
AS3 introduces the OOP paradigm for you to use - this further emphasises the above - you should create classes which define a fixed collection of properties and methods. This way, the intent of each class in your application is clear, and what you expect something to be able to do won't change.
If you absolutely must be able to delete functions, you can assign them to a dynamic object and remove or redefine them with the delete keyword:
var methods:Object = {
something: function():void
{
trace('Still here.');
}
};
methods.something(); // Still here.
delete methods.something;
methods.something(); // TypeError: something is not a function.
methods.something = function():void
{
// Define new function.
}
Or assign an anonymous function to a variable of type Function, from which point you can set the reference to null:
var something:Function = function():void
{
trace("Still here.");
}
something(); // Still here.
something = null;
something(); // TypeError: value is not a function.
something = function():void
{
// Define new function.
}
Related
I have a MovieClip inside library, linkaged to MyObject and it contains a textField.
I don't know how I can access this textField without using the getChildByName method.
Apparently, the 3rd section works when object is on stage (without using addChild). But when using addChild I think there has to be some kind of casting; which I don't know how.
var childElement: MyObject = new MyObject();
childElement.name = "theChildElement";
container.addChild(childElement);
btn.addEventListener(MouseEvent.CLICK, changeText);
function changeText(event: MouseEvent): void
{
var targetBox:MovieClip = container.getChildByName(childElement.name) as MovieClip;
targetBox.textField.text = "hello"; // THIS WORKS
// This works too:
// MovieClip(container.getChildByName("theChildElement"))["textField"].text = "hello"; // THIS WORKS TOO.
// THIS DOESN'T WORK. why?
// container["theChildElement"]["textField"].text = "hello";
}
As confusing as it may seem, instance name, and name are not the same. From your code you should always be able to get to your MC by it's variable name. To get your last like to work you could just use this.
childElement["textField"].text = "hello";
There is a difference between Symbols created by the Flash IDE, which aggregate other DisplayObjects and programmatically created DisplayObjects.
When a DisplayObject is created in the Flash IDE, it's instance name can be used to resolve the instance as a property - which means it can be accessed via []. The [] can be used to access properties or keys of dynamic declared classes - like MovieClip. This necessary because you'll most likely down cast to MovieClip instead of using the symbol class created by Flash. That is not possible when simply using addChild, addChildAt or setChildAt from the DisplayObjectContainer API.
It is always the save way to access it via getChildByNameand check for null because otherwise your app, website or whatever is doomed for 1009 errors as soon as someone is changing the symbols.
I'd create a bunch of helper methods, like
// not tested
function getChildIn(parent:DisplayObjectContainer, names:Array):DisplayObject {
var child:DisplayObject, name:String;
while (names.length > 0) {
name = names.shift();
child = parent.getChildByName(name);
if (!child) {
// log it
return null;
}
if (names.length == 0) {
return child;
}
}
// log it
return null;
}
function getTextFieldIn(parent:DisplayObjectContainer, names:Array):TextField {
return getChildIn(parent, names) as TextField;
}
function getMovieClipIn(parent:DisplayObjectContainer, names:Array):MovieClip {
return getChildIn(parent, names) as MovieClip;
}
Your third method doesn't work because you are trying to call the ChildElement by it's name
without using getChildByName method. On the other hand, you shouldn't call your textField textField, because that's already an actionScript property.
Your should rather call it 'displayText' for example.
For a textField called 'displayText' contained in childElement :
function changeText(event:MouseEvent): void
{
childElement.displayText.text = "hello";
}
Okay so I have a function called changeHandler - it is called by several eventListeners in other functions. I want to write several if statements that evaluate the source of function call and change the dataProvider of my ComboBox depending on the originating function. Example: one of the many functions is called displayCarbs() and has an eventListener like so:
function displayCarbs(event:MouseEvent):void {
myComboBox.addEventListener(Event.CHANGE, changeHandler);
}
(I've removed all of the unnecessary code from the function above)
The if statement inside the changeHandler will look something like this:
if (****referring function = displayCarbs****) {
myComboBox2.dataProvider = new DataProvider(carbItems);
}
I've searched high and low for something that can achieve this, but I just don't have a good enough grasp of AS3 or vocabulary to describe what describe what I mean to get the answer from Google.
The simplest way I can think of... Couldn't you simply create a text string that updates to the name of function before going to changeHandler then in turn changeHandler can check string content and act accordingly..
public var referring_function:String;
function displayCarbs(event:MouseEvent):void
{
referring_function = "displayCarbs";
myComboBox.addEventListener(Event.CHANGE, changeHandler);
}
function displayCarbs(event:Event):void
{
if (referring_function == "displayCarbs")
{ myComboBox2.dataProvider = new DataProvider(carbItems); }
if (referring_function == "displayOthers")
{ myComboBox2.dataProvider = new DataProvider(otherItems); }
// etc etc
}
I cant remember right now if you need == or just = when checking the If statement against strings.
I know there is an accepted answer already, but based on what I gleaned about the problem, here is a solution that wouldn't require adding another variable to check :
function displayCarbs(event:MouseEvent):void
{
myComboBox.addEventListener(Event.CHANGE, changeHandler);
}
function changeHandler(event:Event):void
{
var comboBox:ComboBox = event.target as ComboBox;
if (comboBox.dataProvider == uniqueProvider)
{
myComboBox2.dataProvider = new DataProvider(appropriateItems);
}
}
This should work if the second dataProvider is determined based on the first dataProvider. This of course requires that your uniqueProvider is a class member variable so it has scope within the handler.
I'm pretty positive what I want to do isn't possible with ActionScript, but it would be nice to be wrong.
I need to pass a variable reference to a function, and have the function change the value of the variable.
So, simplified and not in completely correct syntax, something like this:
function replaceValue(element:*, newValue:String):void
{
element = newValue;
}
var variableToModify:String = "Hello";
replaceValue(variableToModify, "Goodbye");
trace(variableToModify) // traces value of 'Hello', but want it to trace value of 'Goodbye'
Of course, in the replaceValue function, element is a new reference to fungibleValue (or, rather, a new reference to fungibleValue's value). So, while element gets set to the value of newValue, fungibleValue does not change. That's expected but totally not what I want, in this case.
There's a similar question, for Ruby, here Changing value of ruby variables/references
As the question points out, Ruby has a way to accomplish this. BUT is there any way to do this in ActionScript?
If so, it's going to make something stupid a lot easier for me.
No it's not possible the function will always get the value and not the reference. But if you are able to call replaceValue why not returning the new value from your function :
function replaceValue(element:*, newValue:String):String
{
// .. do your work
return newValue;
}
var variableToModify:String = "Hello";
variableToModify = replaceValue(variableToModify, "Goodbye");
trace(variableToModify)
If you pass an Object or a Class, you can modify one fiels based on his name as :
function replaceValue(base:Object, fieldName:String, newValue:String):void {
// do your work
base[fieldName] = newValue;
}
var o:Object={ variableToModify:"Hello" };
replaceValue(o, "variableToModify", "Goodbye");
trace(o.variableToModify);
I have a strange issue! I am trying to remove an event listener on a FileReference object by calling a function, but it seems not to be removed, and I do not understand why.
Here is the code:
private function clearFileUploadListeners(file:FileReference, index:String):void {
var dispatchEvent:Function = function(event:Event):void {
dispatch(event.type, event, index);
};
file.removeEventListener(Event.COMPLETE, dispatchEvent);
var bool:Boolean = file.hasEventListener(Event.COMPLETE);
if (bool)
trace("ERROR");
}
When I run this code, the trace actually happens. I don't understand why this boolean returns true, when I just tried to remove the eventListener just above! I guess I am probably doing something really stupid because it seems like a strange error.
I hope someone can please help me on this issue.
EDIT:
I believe it has to do with the fact that the dispatchEvent function is defined inside another function when I add the listener:
private function upload(file:FileReference, index:String):void {
var dispatchEvent:Function = function(event:Event):void {
dispatch(event.type, event, index);
};
file.addEventListener(Event.COMPLETE, dispatchEvent);
}
The problem is that I need to access this "index" variable from the listener, and I can't set it as a global variable as each file has it's own index and it's a burden if I have to extend each event class to keep track of the index (Event, ProgressEvent, ..). I hope someone can please help me on this.
EDIT2:
I actually found a temporary solution, I am not sure if it is the best! I put my removeListener method actually inside the upload method, but made it a variable. As AS3 allows dynamic object, I attached this method to one of my object, and so I just call the reference to the method when necessary. The event is actually removed. Is this a good solution please?
Thank you very much,
Rudy
You're right, it has to do with the fact that you're defining a function inside another function, then using it to handle events.
Each time the function upload is called, it creates a new closure, and assigns a reference to it to the dispatchEvent variable, which is then passed to the addEventListener class. So each time upload is called, it is using a new, different closure in the call to addEventListener. Similarly, in the clearFileUploadListeners function, a new closure is being created on each call (which happens to have the same code each time, but isn't the same function object). The call to removeEventListener does nothing if the given callback has not been added as an event listener for the given event, which is the case here.
To solve your problem, you need to store a reference to the closure that you pass to the addEventListener function. This way, you can get a reference to the same closure that was added when you need to remove it later in clearFileUploadListeners.
You can try something along the lines of the following code (untested):
import flash.utils.Dictionary;
var callbackRegistry:* = new Dictionary();
private function upload(file:FileReference, index:String):void {
var dispatchEvent:Function = generateFileUploadCompleteCallback();
callbackRegistry[file] = dispatchEvent;
file.addEventListener(Event.COMPLETE, dispatchEvent);
}
private function clearFileUploadListeners(file:FileReference, index:String):void {
var dispatchEvent:Function = callbackRegistry[file];
callbackRegistry[file] = null;
file.removeEventListener(Event.COMPLETE, dispatchEvent);
var bool:Boolean = file.hasEventListener(Event.COMPLETE);
if (bool)
trace("ERROR");
else
trace("YAY, ALL OK!");
}
private function generateFileUploadCompleteCallback(index:String):Function {
return function(event:Event):void {
dispatch(event.type, event, index);
};
}
Two other things to note on this subject.
If you must utilize a native Event directly then you should pretty much always make sure and use these last three optional params :
myObject.addEventListener( Event.COMPLETE, myFunction, false, 0, true );
Check Grant Skinner's post on the subject here :
http://gskinner.com/blog/archives/2006/07/as3_weakly_refe.html
And the very best practice of all is to ALWAYS (seriously always) use Robert Penner's Signals (instead of custom events) and his NativeSignals (to wrap needed native Flash events).
Five times faster than Flash's native events.
Always safe with weak references.
Any number of typed payload(s) in each Signal.
Get the SWC here :
https://github.com/robertpenner/as3-signals
Signals were designed to solve the very problem you are having.
Imagine instead of creating an array and managing that to remove all listeners if you could just call :
signalBtnClicked.removeAll();
or
signalBtnClicked.addOnce( function( e : MouseEvent ) : void { /* do stuff */ } );
Knowing that the closure you just created will immediately be dereferenced once it is called and happily go night night when the GC makes its rounds.
I'm having quite some trouble to try and get an app I wrote in AS2 to AS3. The reason I need to go to AS3 is something icky, so I won't go into detail about it.
I've got 90% of the application running with the new code.
Now I've come to the point where I have to convert this code from AS2,
function setAnimation(theObject,id)
{
theObject.vensterid=id;
theObject.onEnterFrame = function()
{
var myHoriTween:Tween = new Tween (this,"_x",Strong.easeOut,this._x,(130+((theObject.vensterid-frameno)*260)),1,true);
}
}
setAnimation(venster0,0);
, to AS3. My attempt of doing this ended up like
function setAnimation(anObject,id) {
var theObject = this[anObject];
theObject.vensterid=id;
function slideHorizontal(event:Event)
{
var myTween:Tween = new Tween (theObject,"x",Strong.easeOut,this.x,(130+((theObject.vensterid-frameno)*260)),1,true);
}
theObject.addEventListener(Event.ENTER_FRAME,slideHorizontal);
}
setAnimation(venster0,0);
and gives me the following non-error (it doesn't show as a compiler error, but as output):
TypeError: Error #1010: A term is undefined and has no properties.
at sliding_windows_as3_fla::SlideMenu_1/setAnimation()
at sliding_windows_as3_fla::SlideMenu_1/frame1()
I think this is very strange since it doesn't say anything about which term (and there are quite a lot) and googling didn't find me an explanation either.
I didn't get the chance to test your code, because it's difficult to set up a context for it, but my thoughts would be:
You should declare the parameter types: function setAnimation(anObject:Object,id:uint):void. It's at least good practice.
var theObject = this[anObject]; is completely unnecessary if your variable anObject is an object. I think var theObject = this[anObject]; doesn't work, theObject ends up being null and that's why you get your error. If you have declared a variable called venster0, that is the instance of a class that extends Object, then you can pass the reference to it without any other trouble.
Depending on the object you work with, theObject.vensterid=id; might not work. The class that theObject instances must have the 'vensterid' property, or you will get `1119: Access of possibly undefined property vensterid through a reference with static type ...
I think your problem here is following string:
var theObject = this[anObject];
Just replace it with
var theObject = anObject;
I hope that's what you need.
Alternatively instead of
setAnimation(venster0,0);
you could pass an instance name (i.e. String):
setAnimation("venster0",0);
That will work because by this['propertyname'] you are actually accessing Object's property by name.
Just going to throw out that using the built-in Tween classes in Flash/Flex is a pain. Look into using Tweening libraries instead: Tweener, TweenLite, etc. They are much easier to work with, and you don't have to worry about maintaining references until the Tween completes.