AS3 call function inside loader event function - actionscript-3

I have a problem to call a function inside a conditional in another function. I've tried it and it works perfectly but it depends on where the call is made.
Process: I have the checkCode(); function that is called when a form is completed and sent.
private function checkCode():void {
var url = "checktrue.php";
var loader:URLLoader = new URLLoader;
var urlreq:URLRequest = new URLRequest(url);
var urlvars:URLVariables = new URLVariables;
loader.dataFormat = URLLoaderDataFormat.VARIABLES;
urlreq.method = URLRequestMethod.POST;
urlvars.codeVar = formattedCode;
urlreq.data = urlvars;
loader.addEventListener(Event.COMPLETE, completed); //Completed function
status.text = "calling loader";
loader.load(urlreq);
}
When php is complete, "completed" is called and:
private function completed(event:Event = null):void {
var loader2: URLLoader = URLLoader(event.target);
var checked:String = loader2.data.checked;
var codetrue:String = loader2.data.codetrue;
if(checked == "1" || codetrue == null || codetrue == "") {
trace("WRONG");
}
else{
download(); //download function
trace("ok");
}
}
Here I get the php vars and check if they are valid to call the download() function.
public function download():void {
req = new URLRequest(proxy + filename);
file = new FileReference();
file.addEventListener(Event.COMPLETE, completeHandler);
file.addEventListener(Event.CANCEL, cancelHandler);
file.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
file.addEventListener(ProgressEvent.PROGRESS, progressHandler);
file.download(req, "file.zip");
}
It is possible this function cannt be called from the "completed" loader function?
Thank you very much!

You need to put the download function in another button for the correct use. Or create your own event.

Related

Variable scope in function closure?

I've just started using nested functions and they come in very handy. However I am running into problems with populating a variable which is later returned by the enclosing function.
The code below is for an AIR project to load some BitmapData. I expected that my variable ("bitmapData") would be populated in the loaderComplete function but it is always returned as null. However, in my trace statements, the image dimensions are being logged, so clearly it has been read.
Is there something wrong with my syntax or my understanding (or both ;-)
private function getBitmapData(url:String):BitmapData
{
var bitmapData:BitmapData;
var bytes:ByteArray = getByteArray(url);
if (bytes == null){
trace("bytes null");
return null;
}
var loader:Loader = new Loader();
loader.loadBytes(bytes);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderComplete);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioErrorListener);
function loaderComplete(event:Event):void
{
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loaderComplete);
loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorListener);
var loaderInfo:LoaderInfo = LoaderInfo(event.target);
trace("loader",loaderInfo.width, loaderInfo.height);
bitmapData = new BitmapData(loaderInfo.width, loaderInfo.height, false, 0xFFFFFF);
trace("bitmapData.rect", bitmapData.rect);
bitmapData.draw(loaderInfo.loader);
}
function ioErrorListener(event:IOErrorEvent):void
{
trace("ioErrorListener", event.errorID);
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loaderComplete);
loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorListener);
}
return bitmapData;
}
public function getByteArray(url:String):ByteArray{
var byteFile:File = new File(url);
if(byteFile.exists && !byteFile.isDirectory){
var fileStream:FileStream = new FileStream();
fileStream.open(byteFile, FileMode.READ);
var tempBytes: ByteArray = new ByteArray();
fileStream.readBytes( tempBytes );
fileStream.close();
return tempBytes;
} else {
trace("file doesnt exist");
return null;
}
}
Loader.loadBytes() is an asynchronous method. The COMPLETE event is not fired in the same frame as the call to loadBytes. Therefore, you're actually attempting to return bitmapData before the code in loaderComplete executes.
You may want to try doing something with callbacks. For example, you can pass a reference to a function as a parameter in getBitmapData, and then call that function in loaderComplete:
private function getBitmapData(url:String, callback:Function):void
{
var bitmapData:BitmapData;
var bytes:ByteArray = getByteArray(url);
if (bytes == null){
trace("bytes null");
callback(null);
}
var loader:Loader = new Loader();
loader.loadBytes(bytes);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderComplete);
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioErrorListener);
function loaderComplete(event:Event):void
{
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loaderComplete);
loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorListener);
var loaderInfo:LoaderInfo = LoaderInfo(event.target);
trace("loader",loaderInfo.width, loaderInfo.height);
bitmapData = new BitmapData(loaderInfo.width, loaderInfo.height, false, 0xFFFFFF);
trace("bitmapData.rect", bitmapData.rect);
bitmapData.draw(loaderInfo.loader);
callback(bitmapData)
}
function ioErrorListener(event:IOErrorEvent):void
{
trace("ioErrorListener", event.errorID);
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loaderComplete);
loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorListener);
}
}
private function handleNewBitmapData(bitmapData:BitmapData):void
{
trace("handled bitmapData.rect", bitmapData.rect);
}
getBitmapData("[some url]", handleNewBitmapData);

Putting Urlloader in a Class

I have searched on google en different pages i found the problem but not the solution.
I have a class i made and that class is called WebServiceController:
public class WebServiceController
{
private var url:String;
private var post:Object=new Object();
private var loader:URLLoader = new URLLoader();
private var postVariable:String="";
private var getVariable:String="";
private var Geladen:Boolean=false;
public function WebServiceController()
{
}
public function postUrlData(u:String,p:Object):String
{
url=u;
post=p;
var urlReq:URLRequest = new URLRequest (url);
var i:int=0;
for(var key:String in post)
{
//trace(key +" = " + post[key]);
if(i==0)
{
// urlVars.key = post[key];
postVariable=postVariable+""+key+"="+post[key];
}
else
{
//urlVars.key = post[key];
postVariable=postVariable+"&"+key+"="+post[key];
}
i++;
}
//trace(postVariable);
var urlVars:URLVariables = new URLVariables(postVariable);
//trace(urlVars);
// Add the variables to the URLRequest
urlReq.data = urlVars;
urlReq.method = URLRequestMethod.POST;
// Add the URLRequest data to a new Loader
//loader.load(urlReq);
// Set a listener function to run when completed
loader.addEventListener(Event.COMPLETE, onLoaderComplete);
// Set the loader format to variables and post to the PHP
loader.dataFormat = URLLoaderDataFormat.VARIABLES;
loader.load(urlReq);
function onLoaderComplete(event:Event):void
{
return loader.data;
}
}
Now from my movieclip i call the next function but it says undefined:
var wb:WebServiceController = new WebServiceController();
trace(wb.postUrlData(url,post));
I dont know how to solve this. I tried different things but it keeps saying undefined.
The URLLoader.load call is executed asynchronously so the data has not been returned when you attempt to trace it out in the class that instantiates your WebServiceController class.
To access the data in the parent class, your best bet is probably to dispatch an event from the WebServiceController class when the data has loaded and catch it in the parent class.
WebServiceController:
public function postUrlData(u:String, p:Object):void
{
url=u;
post=p;
var urlReq:URLRequest = new URLRequest (url);
var i:int=0;
for(var key:String in post)
{
//trace(key +" = " + post[key]);
if(i==0)
{
// urlVars.key = post[key];
postVariable=postVariable+""+key+"="+post[key];
}
else
{
//urlVars.key = post[key];
postVariable=postVariable+"&"+key+"="+post[key];
}
i++;
}
//trace(postVariable);
var urlVars:URLVariables = new URLVariables(postVariable);
//trace(urlVars);
// Add the variables to the URLRequest
urlReq.data = urlVars;
urlReq.method = URLRequestMethod.POST;
// Add the URLRequest data to a new Loader
//loader.load(urlReq);
// Set a listener function to run when completed
loader.addEventListener(Event.COMPLETE, onLoaderComplete);
// Set the loader format to variables and post to the PHP
loader.dataFormat = URLLoaderDataFormat.VARIABLES;
loader.load(urlReq);
}
private function onLoaderComplete(event:Event):void
{
// We can pass the event on like this
dispatchEvent(event);
}
Parent class:
public function initWebServiceController():void
{
var wb:WebServiceController = new WebServiceController();
wb.addEventListener(Event.COMPLETE, onWebServiceControllerDataLoaded);
wb.postUrlData(url, post);
}
private function onWebServiceControllerDataLoaded(event:Event):void
{
// The event target is the URLLoader instance. We can
// access the loaded data via its data property
trace(URLLoader(event.target).data);
}

Add complete contact object from Facebook to SqLite

I can't add name and image from Facebook contacts to SqLite, becouse adding is inside in loop and loader start when Event is Complete. Fllowing code adds data to the database, but in the name of the object is the last person out of the loop. Any thoughts? Thanks!
private var person:PersonVO;
protected function handleFriendsLoad(response:Object, fail:Object):void
{
if (fail) { return }
var friends:Array = response as Array;
var l:uint=friends.length;
for (var i:uint=0;i<l;i++) {
var friend:Object = friends[i];
FacebookDesktop.api('/'+friend.id, loadData);
}
}
private function loadData(object:Object, fail:Object):void
{
if (fail) { return; }
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageToByteArray);
loader.load(new URLRequest(FacebookDesktop.getImageUrl(object.id, 'large')));
person = new PersonVO()
person.name = object.first_name;
}
private function imageToByteArray(event:Event):void
{
var wczytaj:Loader = (event.target as LoaderInfo).loader;
var image:Bitmap = Bitmap(wczytaj.content);
var encoderJpeg:JPEGEncoder = new JPEGEncoder();
var byteArray:ByteArray = encoderJpeg.encode(image.bitmapData);
person.image= byteArray;
insert(person);
}
private function insert(person:PersonVO):void
{
dbStatement.text = "INSERT INTO person (name,image) values(:name,:jpeg)";
dbStatement.parameters[":name"] = person.name;
dbStatement.parameters[":jpeg"] = person.image;
dbStatement.execute();
}
Extend Loader class functionality:
dynamic class DynamicLoader extends Loader{}
Then store whatever you want in instances of DynamicLoader:
private function loadData(object:Object, fail:Object):void
{
if (fail) { return; }
var person:PersonVO = new PersonVO();
person.name = object.first_name;
var loader:DynamicLoader = new DynamicLoader();
loader.person = person;
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageToByteArray);
loader.load(new URLRequest(FacebookDesktop.getImageUrl(object.id, 'large')));
}
private function imageToByteArray(event:Event):void
{
var wczytaj:DynamicLoader = (event.target as LoaderInfo).loader as DynamicLoader;
var image:Bitmap = Bitmap(wczytaj.content);
var encoderJpeg:JPEGEncoder = new JPEGEncoder();
var byteArray:ByteArray = encoderJpeg.encode(image.bitmapData);
var person:PersonVO = wczytaj.person;
person.image= byteArray;
insert(person);
}
I have not used private var person:PersonVO;. So if you are not using it in the other methods of your class, you could remove it completely.

AS3/AIR: IOStream Error when trying to upload files

I'm making an AIR app in which the user drags and drops image files onto the stage, the app then uploads those dropped images to the site imgur.com, and then returns with links to the images (in XML format).
I am having two issues:
the program works successfully with a very small file, however anything larger (1mb or more), I get an IOStream error 2023. Imgur supports uploads of up to 10mb so I know it must be something on my end.
I would like to be able to drop multiple image files at once into the program, and have it upload all of them (either synchronously or asynchronously, it does not matter). Right now the program gives errors when I attempt to do this (something along the lines of the byteArray having to be greater than 0).
Below is the code in question which is giving me issues. (thank you for your help in advanced)
private function doDragDrop(e:NativeDragEvent):void
{
trace("doDragDrop() called.");
var dropFiles:Array = e.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
for each (var file:File in dropFiles)
{
switch (file.extension.toLowerCase())
{
case "jpg" :
case "jpeg" :
case "gif" :
case "png" :
case "apng" :
case "tiff" :
case "bmp" :
case "pdf" :
case "xcf" :
trace("file Extension Check = passed");
addImage(file.nativePath);
break;
//error handling for non-supported filetypes
default :
trace("ERROR: Unsupported File Type Detected!");
}
}
}
private function addImage(nativePath:String):void
{
trace("addImage() called.");
trace("NativePath is: " + nativePath);
//var file:File = new File(nativePath);
var file:File = File.desktopDirectory.resolvePath(nativePath);
var ba:ByteArray = new ByteArray();
var stream:FileStream = new FileStream();
stream.open(file, FileMode.READ);
stream.readBytes(ba);
stream.close();
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, fileLoaded);
loader.loadBytes(ba);
}
private function fileLoaded(e:Event):void
{
trace("fileLoaded() called.");
var bitmap:Bitmap = Bitmap(e.target.content);
var bitmapData:BitmapData = bitmap.bitmapData;
var png:ByteArray = PNGEncoder.encode(bitmapData);
urlLoader = new URLLoader();
urlLoader.dataFormat = URLLoaderDataFormat.VARIABLES;
urlLoader.addEventListener(Event.COMPLETE, onCookieSent);
urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
urlLoader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
var vars:String = "?key=" + API_KEY + "&name=name&title=title";
var request:URLRequest = new URLRequest(UPLOAD_URL + vars);
request.contentType = "application/octet-stream";
request.method = URLRequestMethod.POST;
request.data = png;
urlLoader.load(request);
}
private function onCookieSent(e:Event):void
{
trace("onCookieSent() called.");
var res:XML = new XML(unescape(urlLoader.data));
var resultsList:XMLList = res.links;
trace(resultsList);
}
private function onIOError(e:IOErrorEvent):void
{
trace("ioErrorHandler: " + e);
TweenLite.to(tv_mc, 2, {alpha:0.5, scaleX:1.0, scaleY:1.0, ease:Elastic.easeOut});
// Handle error
}
private function onSecurityError(e:SecurityErrorEvent):void
{
trace("securityErrorHandler: " + e);
TweenLite.to(tv_mc, 2, {alpha:0.5, scaleX:1.0, scaleY:1.0, ease:Elastic.easeOut});
// handle error
}
//When the dragged object leaves the drop point, do this
private function doDragExit(e:NativeDragEvent):void
{
trace("doDragExit() called.");
TweenLite.to(tv_mc, 2, {alpha:0.5, scaleX:1.0, scaleY:1.0, ease:Elastic.easeOut});
}
after doing this:
var ba:ByteArray = new ByteArray();
var stream:FileStream = new FileStream();
stream.open(file, FileMode.READ);
stream.readBytes(ba);
stream.close();
you already have a ByteArray of the file/image. can't you just send this one...
private function addImage(nativePath:String):void
{
trace("addImage() called.");
trace("NativePath is: " + nativePath);
//var file:File = new File(nativePath);
var file:File = File.desktopDirectory.resolvePath(nativePath);
var ba:ByteArray = new ByteArray();
var stream:FileStream = new FileStream();
stream.open(file, FileMode.READ);
stream.readBytes(ba);
stream.close();
urlLoader = new URLLoader();
urlLoader.dataFormat = URLLoaderDataFormat.VARIABLES;
urlLoader.addEventListener(Event.COMPLETE, onCookieSent);
urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
urlLoader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
var vars:String = "?key=" + API_KEY + "&name=name&title=title";
var request:URLRequest = new URLRequest(UPLOAD_URL + vars);
request.contentType = "application/octet-stream";
request.method = URLRequestMethod.POST;
request.data = ba;
urlLoader.load(request);
}

AS3 - Remove Child Problem

I'm using the following code to display an advertisement in a mobile game that I'm working on. It works fine but I don't know what to put in the clickStart function to remove the advertisement from the stage before the game plays. I've been playing around with removeChild but can't seem to get it to work.
stop();
startButton.addEventListener(MouseEvent.CLICK,clickStart);
function clickStart(event:MouseEvent) {
gotoAndStop("play");
}
var request:URLRequest = new URLRequest("http://soma.smaato.com/oapi/reqAd.jsp");
var variables:URLVariables = new URLVariables();
variables.adspace = "0";
variables.pub = "0";
variables.devip = "127.0.0.1";
variables.format = "IMG";
variables.adcount = "1";
variables.response = "XML";
request.data = variables;
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, onComplete);
loader.load(request);
function onComplete(e:Event):void
{
var data:XML = new XML(loader.data as String);
var status:String = data.*::status.toString();
if(status == "success")
{
var ad:XMLList = data.*::ads.*::ad;
var link:String = ad.*::link.toString();
var l:Loader = new Loader();
l.load(new URLRequest(link));
addChild(l);
l.x = 135;
l.y = 265;
var clickurl:String = ad.*::action.#target.toString();
l.addEventListener(MouseEvent.CLICK, onAdClick);
function onAdClick(e:MouseEvent):void
{
var request:URLRequest = new URLRequest(clickurl);
navigateToURL(request);
}
}
}
You need to move the declaration of the Loader outside of the onComplete function, since the variable runs out of scope.
var l:Loader = new Loader();
You could try placing it on the same scope as these:
var request:URLRequest = new URLRequest("http://soma.smaato.com/oapi/reqAd.jsp");
var variables:URLVariables = new URLVariables();
then you should be able to update your clickStart function to something like this:
function clickStart(event:MouseEvent) {
removeChild(l);
gotoAndStop("play");
}