as3 return value on loader complete - function

I am trying to get my function to return a value from a php script once it has loaded. I am having issues with the 'return' aspect. Trying to the the value of 'TheLink" from a function with a 'return' in it. It's usually null. What am I doing wrong here?
var theLink = loadAudio();
public function loadAudio():String
{
var req:URLRequest = new URLRequest("myScript.php");
var loader:URLLoader = new URLLoader(req);
loader.dataFormat = URLLoaderDataFormat.VARIABLES;
loader.addEventListener(Event.COMPLETE, Finished);
function Finished(e:Event)
{
var theValue = JSON.parse(e.target.data.audioLink);
return theValue;
}
}

A lot of things are wrong in your code but more important is that you cannot escape the asynchronous nature of AS3.
First thing first, even if AS3 wasn't asynchronous your code would still not work. The "loadAudio" never returns anything so theLink can never get any data. The 'Finished' method is the one return something but there's no variable to catch that data either.
Now the real stuff, AS3 is asynchronous that means that things will happen at a later time and this is why you need to pass an event listener in order to 'catch' when things happen. In your case the Event.COMPLETE will trigger at a later time (asynchronous) so there's no way for a variable to catch the result before the result is actually available so:
var theLink:Object = loadAudio();//this is not possible
The correct way is:
private var loader:URLLoader;//avoid GC
private var theLink:Object;//this will store result when available
//I assume you are using a class
public function MyClass()
{
loadAudio();//let's start loading stuff
}
private function loadAudio():void
{
var req:URLRequest = new URLRequest("myScript.php");
loader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.VARIABLES;
loader.addEventListener(Event.COMPLETE, handleLoaded);
loader.load(req);
}
private function handleLoaded(e:Event):void
{
theLink = JSON.parse(e.target.data.audioLink);
//done loading so store results.
}

Related

JSON.parse(...).reelarray is null - ActionScript

in return i am getting null value
public function spin()
{
var decoded : Object;
trace("i am innnnnnn");
var sendLoaders:URLLoader;
var sendRequests:URLRequest;
sendLoaders = new URLLoader();
sendRequests = new URLRequest("http://localhost/getspinvalue/4");
var difvar:Array = [];
sendLoaders.addEventListener(Event.COMPLETE, botCompleted);
sendLoaders.load(sendRequests);
function botCompleted(e:*)
{
decoded = JSON.parse(e.currentTarget.data);
}
trace(decoded);
return decoded.reelarray;
}
well, the sendLoaders.load() is an asynchronous event, your function returns null since the botCompleted() function hasnt fired when the function returns
You need to continue the execution inside you botComplete function (if you need to do different things after each spin() you can pass a function that gets executed)
public function spin() {
var decoded : Object;
trace("i am innnnnnn");
var sendLoaders:URLLoader;
var sendRequests:URLRequest;
sendLoaders = new URLLoader();
sendRequests = new URLRequest("http://localhost/getspinvalue/4");
var difvar:Array = [];
sendLoaders.addEventListener(Event.COMPLETE, botCompleted);
sendLoaders.load(sendRequests);
trace("request sent")
}
function botCompleted(e:*) {
decoded = JSON.parse(e.currentTarget.data);
trace("data recieved:" + decoded)
//CONTINUE EXECUTION HERE
}
URLLoader.load is an asynchronous method, it means that it spawns a process to load URL, and the execution of spin continues. So it returns a value at once. The botCompleted function is executed when the request is fulfilled, later. Something like that:
sendLoaders.load()
return value
botCompleted()
So you should rely on the botCompleted function, rather than on the return value. All the logic that depends on the decoded result should be triggered inside the botCompleted function.
function botCompleted(e:Event):void {
decoded = JSON.parse(e.currentTarget.data);
handleDecodedResult(decoded);
}
i want my spin method to return the decoded value .so how can i change
my code.
This is not possible. The JSON data is loaded asynchronously, but the function returns synchronously. In other words, the spin() function returns immediately (like all functions do), but the URLLoader doesn't complete until later in time. It doesn't matter that the botCompleted handler is written before your return statement, it won't get called until later. This is what event handlers are for: to handle asynchronous events.
What you can do is pass in callback functions. For example:
function spin(callback:Function):void {
var loader:URLLoader = new URLLoader();
// .. load
loader.addEventListener(Event.COMPLETE, complete);
function complete(e:Event):void {
var decoded:Object = JSON.parse(e.target.data);
callback(decoded);
}
}
Now you can call your spin function and pass an anonymous function in the context that you call spin, which almost makes it look synchronous:
spin(function(data:Object):void {
trace(data);
// Do stuff with data here
});
// Note: data is not available yet from here, only from inside the callback above
This is a common practice (in both AS3 and JS), though not without its pitfalls.

AS3 image loading content is always null

I have a problem with my assets loader I've created for my flash app. In a function I try to load an external image and return it from this function. My problem is that I always get loader.content set to null. This how my code looks like:
public static function loadImage(path:String):BitmapData
{
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, check);
if (path == "")
loader.load(new URLRequest("images/default.png"));
else
loader.load(new URLRequest("images/" + path));
var image:Bitmap = new Bitmap((loader.content as BitmapData));
return image.bitmapData;
}
public static function check(e:Event):void
{
trace("Loading completed");
e.target.removeEventListener(Event.COMPLETE, check);
}
Any ideas???? I've also included my event listener which does launch.
I'm pretty sure it's because the loader works asynchronously, but I have no idea how to modify it to be able to return the image from the function.
Thanks in advance!
I'm pretty sure it's because the loader works asynchronously
Correct
but I have no idea how to modify it to be able to return the image from the function
There is no way to do that.
Why?
Because it is asynchronous.
You can't return a result of a request straight after the request has been made.
The execution of the code does not pause and wait for the response to come back, so your function will hit the return statement before you get the data, and that is why it is returning null.
The only way to handle this is to listen for the response (Event.COMPLETE) and run a callback function after the response from the server has been received.
So following your code example, you could do:
private static var _callback :Function;
public static function loadImage(path:String, callback:Function):void
{
_callback = callback;
// ....
and then:
public static function check(e:Event):void
{
// ...
_callback( whateverYouWantToReturnGoesHere );
This should work assuming that you only have one image loaded at a time (as your methods are static), otherwise you will need to implement some sort of request queue handling.
I hope this helps.
Your getting a 'null' because you're referring to loader.content too soon. Here's a simplified version that works, just fine, in a timeline:
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, check);
loader.load(new URLRequest("images/default.png"));
function check(e:Event):void
{
var bmd:BitmapData = new BitmapData(195,130,false,0xFFFFFFFF)
var image:Bitmap = new Bitmap(bmd);
bmd.draw(loader.content);
trace(loader.content);
trace("Loading completed");
addChild(image);
e.target.removeEventListener(Event.COMPLETE, check);
}
You can put it back into a form suitable for your classes.
You should say:
var bitmapData:BitmapData;
and
var image:Bitmap = new Bitmap(event.target.content.bitmapData)
instead of
var image:Bitmap = new Bitmap((loader.content as BitmapData));

Returning a string in Action Script 3.0

I'm really not familiar with Action Script 3 at all but I am with other languages.
I'm hoping someone could help me.
I'm attempting to make a modification to JWplayer so that an rtmp stream is retrieved via a PHP script rather than it being supplied in the HTML.
The code I currently have is below:
function useData(event:Event):void {
var data:String = event.target.data.toString();
}
/** Load content. **/
override public function load(itm:PlaylistItem):void {
_item = itm;
_position = 0;
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, useData);
loader.load(new URLRequest("http://192.168.0.12/phpauth/play1.php"));
// Set Video or StageVideo
if(!_video) {
_video = new Video(320, 240);
_video.smoothing = true;
_video.addEventListener('renderState', renderHandler);
// Use stageVideo when available
if (_stageEnabled && RootReference.stage['stageVideos'].length > 0) {
_stage = RootReference.stage['stageVideos'][0];
_stage.viewPort = new Rectangle(0,0,320,240);
_stage.addEventListener('renderState', renderHandler);
}
attachNetStream(_stream);
}
// Load either file, streamer or manifest
if (_item.file.substr(0,4) == 'rtmp') {
// Split application and stream
var definst:Number = _item.file.indexOf('_definst_');
In the load function the file name to play is held in _item.file. I'm trying to make a call to a php script which then overwrites the value in _item.file. I've confirmed that the php is being called but I don't know how to get the data from the data string in the useData function into the _item.file string.
Any help would be really appreciated - I suspect this is a simple one but my lack of AS3 knowledge is making it really difficult.
Thanks,
Your problem basically about how to access a local variable in an event handler. A quick and dirty way can be to have an anonymous function used as a handler like:
loader.addEventListener(Event.COMPLETE, function(event:Event):void {
var data:String = event.target.data.toString();
_item.file = data;
});
This approach would work, because this anonymous function has access to the local variables inside load function as is. But, you need to be cautious that the anonymous function uses the variable exactly as the calling function is using. So, let's say there is a loop in load function and _item changes in every iteration of the loop. For that scenario, when load handler gets called, its _item would also have changed to the object which was last assigned to _item.
A far cleaner and OO approach can be to have a handler class like:
package {
public class LoadHandler {
private var _item:PlaylistItem;
public function LoadHandler(item:PlaylistItem) {
_item = item;
}
public function loadHandler(event:Event):void {
var data:String = event.target.data.toString();
_item.file = data;
}
}
and then have loader.addEventListener(Event.COMPLETE, (new LoadHandler(_item)).loadHandler). Hope that helps. BTW, LoadHandler could be made more generic to take and array of objects to be used and a callback function. loadHandler function, then could just call callback function with that array of objects.
If you are returning a simple string from PHP you should be able to use
event.target.data;
e.g. from PHP... echo "hello";
var data:String = event.target.data
You could try tracing the response to ensure you are getting something back from PHP.
You can either test this from within the IDE or install the Debug version of the Flash Player browser plugin.
trace("Response from PHP: "+event.target.data);
_item.file = event.target.data;
trace("_item.file: "+_item.file);

Running-order of nested function-calls delayed/altered due to URLloader in AS3?

First of all: English is not my first language. ;-)
I am compiling the following code:
var sqldata:String;
function sql(saveorload,sqlstring) {
var sqlloader = new URLLoader();
var sqlrequest = new URLRequest("http://***/sql.php");
sqlrequest.method = URLRequestMethod.POST;
sqlloader.addEventListener(Event.COMPLETE, sqldonetrace);
var variables:URLVariables = new URLVariables();
variables.sqlm = saveorload;
variables.sqlq = sqlstring;
sqlrequest.data = variables;
sqlloader.load(sqlrequest);
}
function sqldonetrace(e:Event) {
sqldata = e.target.data;
}
sql("1","SELECT * FROM songs WHERE `flag2` LIKE '0'");
trace (sqldata);
So, here comes the problem:
"sqldata" is traced as "null". AS3 seems to run "sql", then "trace" and then "sqldone", but i would need sql -> sqldone -> trace...
I can't put the trace-command in the sqldone-function because it is stored as *.as and loaded at different points in my .swf and not always followed by only a trace-command.
Any Ideas/hints/flaws in script?
Actionscript is, by design, an event driven language. It also guarantees that the code executes in a single thread i.e. if a function call starts, no other(new call) actionscript code would execute until the first call finishes.
That being said, what you should have is to pass a complete handler to sql(...).
function sql(saveorload:String, sqlstring:String, completeHandler:Function):void
{
var sqlloader = new URLLoader();
var sqlrequest = new URLRequest("http://***/sql.php");
sqlrequest.method = URLRequestMethod.POST;
sqlloader.addEventListener(Event.COMPLETE, completeHandler);//tell urlloader to use the complete handler passed in parameters
var variables:URLVariables = new URLVariables();
variables.sqlm = saveorload;
variables.sqlq = sqlstring;
sqlrequest.data = variables;
sqlloader.load(sqlrequest);
}
And then use it from some other place like:
sql("1","SELECT * FROM songs WHERE `flag2` LIKE '0'", sqldonetrace);
function sqldonetrace(e:Event)
{
var sqldata:String = e.target.data;
trace (sqldata);
}
Also, I think you should check for error events from urlloader. Pass another parameter to sql as errorHandler

Refreshing every XX seconds

I am new to actionscript and flash, but i managed to make code that gets data from php file and refresh result every 30 seconds:
var timerRefreshRate:Number = 30000;
var fatherTime:Timer = new Timer(timerRefreshRate, 0);
fatherTime.addEventListener(TimerEvent.TIMER, testaa);
fatherTime.start();
function testaa(event:Event):void{
var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.VARIABLES;
loader.addEventListener(Event.COMPLETE,varsLoaded);
loader.load(new URLRequest("data.php"));
function varsLoaded (event:Event):void {
this.opaqueBackground = loader.data.color;
title.text=loader.data.title;
banner_text.text=loader.data.text;
}
}
But now i am facing 2 problems:
1.) User must wait 30 seconds for movie to load first time
2.) Setting background color does not work any more.
What am i doing wrong?
You can call your function once to load immediately without waiting 30 seconds. Just change the parameters of the function to default to a null event:
function testaa(event:Event = null):void{
//...
}
Now you can call the function like so:
//...
fatherTime.start();
testaa();
So you start the timer but immediately run the function once.
For your second problem, the issue is most likely that you are using a nested function, so this does not refer to your class but rather the testaa function. Nested functions are bad practice in general and you should avoid them if possible. Move the function and loader reference outside and it should work. Final result should be something like this:
var loader:URLLoader;
var timerRefreshRate:Number = 30000;
var fatherTime:Timer = new Timer(timerRefreshRate, 0);
fatherTime.addEventListener(TimerEvent.TIMER, testaa);
fatherTime.start();
testaa();
function testaa(event:Event = null):void{
loader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.VARIABLES;
loader.addEventListener(Event.COMPLETE,varsLoaded);
loader.load(new URLRequest("data.php"));
}
function varsLoaded (event:Event):void {
this.opaqueBackground = loader.data.color;
title.text=loader.data.title;
banner_text.text=loader.data.text;
}