AS3 Putting function blah(){ around code generates errors on lines of code I dont have - actionscript-3

I've got a block of code that's doing what I want - it generates a grid of MC's.
As soon as I put something like function blah() around it, it starts generating errors indicating lines of code I don't have e.g.
TypeError: Error #1010: A term is undefined and has no properties.
at flightCellMaker_fla::MainTimeline/myXMLtrace() [flightCellMaker_fla.MainTimeline::frame1:87]
at flightCellMaker_fla::MainTimeline/processFPBxml() [flightCellMaker_fla.MainTimeline::frame1:52]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at flash.net::URLLoader/onComplete()
When I take the function out, it does what I want it to do. What's up with that?
var testXML:XML;
var myFPBxml:XML;
// Initialise a URLLoader to get XML data from XML file
var myFPBLoader:URLLoader = new URLLoader();
myFPBLoader.load(new URLRequest("flightPlannerBoard.xml"));
// Check XML data fully loaded
myFPBLoader.addEventListener(Event.COMPLETE, processFPBxml);
// Once the flight board planning data is loaded, save it to a variable
function processFPBxml(e:Event):void {
myFPBxml = XML(e.target.data);
myXMLtrace();
}
// Grab the XML data load completed and make it available elsewhere
function myXMLtrace(){
testXML = XML(myFPBxml);
}
trace("***********************" + testXML.*); This throws an error (not within myXMLtrace tho)
OK, so here's the rest of the code that will run correctly on it's own but not in a function:
// Create and place all the flight cells for planning and drag and drop
// Setup 2 loops: j for columns and i for Rows
for (var j:Number =0; j < rowNum; j++){
for (var i:Number =0; i<9; i++){
// Create copies of flightCell for board grid
var my_mc = new flightCell();
my_mc.name = "mc"+i+j;
addChild(my_mc);
// Set event Listeners on all Child objects
my_mc.myDragShape.addEventListener(MouseEvent.MOUSE_OVER, fl_MouseOverHandler);
my_mc.myDragShape.addEventListener(MouseEvent.MOUSE_OUT, fl_MouseOutHandler);
my_mc.myDragShape.addEventListener(MouseEvent.MOUSE_DOWN, fl_MouseDownHandler);
my_mc.myDragShape.addEventListener(MouseEvent.MOUSE_UP, fl_MouseUpHandler);
Object(this).my_mc.yellowHiLite.visible = false;
//cellPos[j] = myXML.cellPosX[j];
//trace(stage.myXML.*);
//trace(my_mc.name);
my_mc.x = (100 + colWidth);
my_mc.y = myRowHeight;
colWidth = colWidth + 155;
//trace(myXML.*);
cellArray[arrayCount] = [my_mc.x, my_mc.y];
trace("CellArrayCount = " + cellArray[arrayCount]);
arrayCount = arrayCount + 1;
}
myRowHeight = myRowHeight + 105;
colWidth = 50;
}

Your trace is throwing an error because it is being executed before the XML is loaded.
ActionScript is asyncronous, which means that while the XML is being loaded, the program execution carries on going, and looks something like this:
Declare testXML:XML and myFPBxml:XML
Create loader and start loading
Add a listener for load completion
Trace testXML
Execute processFPBxml when the XML is loaded
If you move your trace into the myXMLTrace function then it will work correctly.
With the newly added code, the problem is with this line:
Object(this).my_mc.yellowHiLite.visible = false;
There is no need to use the this keyword at all here. This will work inside or outside a function:
my_mc.yellowHiLite.visible = false;
The reason your code fails inside a function is because inside and outside the function this will be the scope of the object in which this code resides. However, when you put the code into a function, the reference you create - my_mc - is scoped locally to the function, not to the parent object, and so this.my_mc is undefined, because this is not the function scope.

Are you taking the code out of the function it's currently in and calling the new function from where the code used to be? Or are you trying to define a function variable?
If you're only putting function blah() { ... } around code in the same place it is currently running, you'll get a syntax error for sure. In that case, try:
var blah:Function= function() { ... };
blah();

If you declare variables within a function they fall inside the scope of the function only.
It sounds like you are trying to access variables from elsewhere in your code.
So what you need to do is declare your variables outside of the function. e.g.
var one:VarType;
var two:VarType;
function blah():void {
trace(one);
}

Related

Cant call function from within object after saving with SharedObject

tl;dr --- I'm trying to create an object and have the name of a function inside that object, then save the object, load it later, and be able to call the function e.g. myFunction on the Main.as, based on the obj.fun() where obj.fun = myFunction or obj.fun = "myFunction";
I create a global variable
var master = {};
I create an object thusly
createMyObject():Object
{
obj = {
name:"myObject",
fun:myFunctionInMain
}
return obj
}
I then push the obj into an Array
master.myArray.push(obj);
Then I save
save.data.master = master;
Then I load
master = save.data.master;
Then I trace my object name like this:
trace(master.myArray[0].name) // output is correct "myObject" so the save and load worked
but when I call the function
master.myArray[0].fun();
it says value is not a function.
This works fine until I save then load... It's as if it isn't saving the function inside the object.... so I tried to put the function in quotes, inside the object and it saves the string, but I can't figure out how to call the function from that after I save it.
I've tried
master.myArray[0][master.myArray[0]]() // didn't work
I've tried
var fun:String = master.myArray[0]fun;
master.myArray[0][fun]() // didn't work
I've tried
var fun:Function = master.myArray[0].fun;
fun(); // didn't work
I thank you very much for any insight here... I've been calling functions from within objects for a while now, but now that I want to save and load, I am seeing this isn't going to work like that.
I think I found it.
var functionName:String = master.myArray[0].fun; // where master was saved in save.data.master
var newFun:Function = this[functionName];
newFun();
Seems to work.

Error 1191 - Basic Input Calculator in AS3

I am trying to make a basic input calculator for class, but I am constantly encountering problems when I solve the old one.
Here is what I have so far:
var answer
import flash.events.MouseEvent;
plus.addEventListener(MouseEvent.CLICK,aaa);
function aaa(e:MouseEvent)
{
var a:Number = Number(input1.text) + Number(input2.text)
a.text = String(a);
}
The problem that I am having right now is 1119:Access of possibly undefined property undefined property text through a reference with static type Number
For starters, the line you declare the variable a has no semicolon:
var a:Number = Number(input1.text) + Number(input2.text) // missing semicolon
Secondly, you define a to be a Number. The data type Number only has public methods and constants, not public variables, and none of its methods are text. Thus a.text gives you the error. AS3 - Number Reference
Thirdly, the Number data type has a method called toString. Therefore, simply call a.toString() instead of String(a).
Lastly, if I knew what you were trying to do I would provide insight.
Update
Try the following code out and let me know in the comments how it turns out.
import flash.events.MouseEvent; // handle imports before anything else
var answer:String = ""; // holds the result of the addition as a String
// add a mouse click handler to the 'plus' object
plus.addEventListener(MouseEvent.CLICK, plusOnClick);
// 'plusOnClick' is the 'plus' object's mouse click handler
function plusOnClick(e:MouseEvent)
{
// 'result' is used to hold the result of the addition as a Number
var result:Number = Number(input1.text) + Number(input2.text)
// set 'answer' to the String representation of 'result'
answer = result.toString();
trace("The result of the addition is " + answer);
}

closures with popups using flex 4.6

I have this custom event handler that shows a popup and accepts input from the user:
private var mySkinnablePopupContainer:MySkinnablePopupContainer;
private function handleShowGridPopupEvent(event:ShowGridPopupEvent):void {
var mouseDownOutSideHandler:Function = function(mdEvent:FlexMouseEvent):void {
// At this point, event.targetControl contains the wrong object (usually the previous targetControl)
if (mdEvent.relatedObject != event.targetControl) {
mySkinnablePopupContainer.close();
}
}
var gridPopupSelectionHandler:Function = function(popEvent:PopUpEvent):void {
if (!popEvent.commit) return;
// At this point, event.targetData contains the wrong object (usually the previous targetData)
myModel.doSomethingWithData(popEvent.data.selectedItem, event.targetData);
}
if (!mySkinnablePopupContainer) {
mySkinnablePopupContainer = new MySkinnablePopupContainer();
mySkinnablePopupContainer.addEventListener(PopUpEvent.CLOSE, gridPopupSelectionHandler);
mySkinnablePopupContainer.addEventListener(FlexMouseEvent.MOUSE_DOWN_OUTSIDE, mouseDownOutSideHandler);
}
// At this point, event.targetData contains the correct object
mySkinnablePopupContainer.dataProvider = getMyDPArrayCollection(event.targetData);
mySkinnablePopupContainer.open(this);
var point:Point = event.targetControl.localToGlobal(new Point());
mySkinnablePopupContainer.x = point.x + event.targetControl.width - mySkinnablePopupContainer.width;
mySkinnablePopupContainer.y = point.y + event.targetControl.height;
}
Every time the function handler gets called, it will have the correct ShowGridPopupEvent object but by the time it calls the
gridPopupSelectionHandler, it will contain the old object from a previous call. It works the first time, subsequent calls fails.
Somehow the reference to the event object changed somewhere in between before opening the popup and after.
Any idea what am I doing wrong here? Is this a bug with flex?
found the prob. since im attaching listener only once, it will reference the old listener, with the reference to the old data. i guess i was expecting its reference to be updated whenever i create the closure. not in this case. possible fix is to remove the listener and re-add it again but I abandoned the idea of using closures, and aside from what RIAStar mentioned, it is also impractical as it only gives more overhead by creating a new function for every invocation of the handler.

ActionScript 3.0 Error #1010 - preloader function

I am a Flash and ActionScript newbie. I am trying to follow a video tutorial to make a preloader and I'm having a problem that the video didn't seem to address. I believe I have entered in all of the code correctly from the video. This is it:
stop();
addEventListener(Event.ENTER_FRAME, loaderF);
function loaderF(e:Event):void{
var toLoad:Number = loaderInfo.bytesTotal;
var loaded:Number = loaderInfo.bytesLoaded;
var total:Number = loaded/toLoad;
if( loaded == toLoad ){
removeEventListener(Event.ENTER_FRAME, loaderF);
gotoAndStop(2);
} else {
preloader_mc.preloaderFill_mc.scaleX = total;
preloader_mc.percent_txt.text = Math.floor( total * 100 ) + "%";
preloader_mc.ofBytes_txt.text = loaded + "bytes";
preloader_mc.totalBytes_txt.text = toLoad + "bytes";
}
}
What I typed in doesn't generate a compiler error, but the output tells me:
TypeError: Error #1010: A term is undefined and has no properties.
at preloader_fla::MainTimeline/loaderF()
And since I really don't have any experience outside of what I'm learning from this tutorial series, I don't know what to do to fix this.
I don't use Flash CS5, but you should be able to get the line # for where the error is occurring, I believe, by executing the SWF by pressing CTRL+SHIFT+ENTER.
Once you get the line number, you should see that something on that line is null or not defined. The error says it occurs in the function loaderF(), and looking at that code the only place such an error could occur is in the else block:
} else {
preloader_mc.preloaderFill_mc.scaleX = total;
preloader_mc.percent_txt.text = Math.floor( total * 100 ) + "%";
preloader_mc.ofBytes_txt.text = loaded + "bytes";
preloader_mc.totalBytes_txt.text = toLoad + "bytes";
}
In the above code block, one of these things is not defined:
preloader_mc.preloaderFill_mc,
preloader_mc.percent_txt,
preloader_mc.ofBytes_txt,
preloader_mc.totalBytes_txt
Maybe your preloader movie clip is missing one of these objects...
First, you'll want to turn on debugging found under (File > Publish Settings > Flash (.swf) > Permit Debugging). This will provide line numbers and allow additional debugging to help track down errors.
Secondly, in the code sample you've provided, you haven't declared a loader, so when you call on loaderInfo, it makes sense that flash complains about "a term is undefined". Although, technically, the loaderInfo object is a child of the event object. Thus, loaderInfo.bytesTotal would become e.loaderInfo.bytesTotal, assuming you added the event listener to the loader object; currently yours is added to the timeline.
Bookmark Adobe's Actionscript 3.0 Reference. Use it. As you begin your journey in Flash, this will be your indispensable handbook to speaking AS3. Specifically, you'll want to refer to the Loader class.
Here's what you're likely missing in your code:
var myLoader:Loader = new Loader();
myLoader.load(new URLRequest("path/to/my/file"));
Your function loaderF is being called during every frame update to the screen (likely every .034 seconds). You'd probably be happier with ProgressEvent.PROGRESS instead of Event.ENTER_FRAME. If so, you'll also want to catch the complete event, and that'd look like this:
myLoader.addEventListener(Event.COMPLETE, loadComplete);
myLoader.addEventListener(ProgressEvent.PROGRESS, loadProgress);
function loadComplete(e:Event):void {
// Stuff to do when the file finishes loading.
}
function loadProgress(e:Event):void {
var current:int = e.bytesLoaded;
var total:int = e.bytesTotal;
var percent:Number = current/total;
// Update the readout of your loading progress.
}
Hopefully that points you in the right direction. :)

Passing local variable to loader anonymous handler function

Why isn't this working as I am thinking it would:
var i:int=-1;
for each(obj in myData)
{
i++;
var loader:Loader=new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,function(event:Event)
{
trace(i);
});
}
There are 3 objects in myData and the trace statement looks like:
2
2
2
Instead of:
0
1
2
If I add i to an array (like myArr.push(i)) it will have 3 elements, 0, 1 and 2.
Any ideas?
Thank you.
That's a very bad approach you've taken... Just don't do any of those things you are trying to do, and it'll be fine... No point in using anonymous function here (it's never actually in AS3), no point to use for-each, because what you need is for(;;). You use dynamic typing for no benefit what so ever (there's no benefit in dynamic typing in AS3 and never was anyway). And, yeah, the closure will capture the context, the context has only one i, and it's value is 2, so the first trace is what you should expect.
What you should be doing - store the loaders in some data structure and fetch them from that data structure later (when you need that identifier). And please, for the sake of us users, load whatever you are trying to load sequentially - because if you don't, we'll get the IO errors you aren't handling...
First let me tell you why it doesn't work as you expect.
What is happening is, the for is looping through your elements, and creates all the loaders, incrementing i, but the Event.COMPLETE happens sometime later, where the i is already at the value 2, so that's why you get that output.
As wvxvw suggested, you need some more data structure, something like this:
class MyLoader {
private var i: int;
private var loader: Loader;
function MyLoader(i:int) {
this.i = i;
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaded);
}
function onLoaded(event:Event)
{
trace(i);
}
}
And you will use it in your loop:
var i:int = 0;
for each(obj in myData) {
var loader:MyLoader=new MyLoader(i++);
}
Of course, you will need to add lots more to that MyLoader, like handling the errors, and pass more meaningful things to make everything work.