Loading swf and using it through interface - actionscript-3

I've created simple swf with interface:
public class Test extends MovieClip implements ITest
{
public function Test()
{
Security.allowDomain("*");
Security.allowInsecureDomain("*");
}
public function speak(str):String
{
trace(str);
return "yeah";
}
}
ITest:
public interface ITest {
// Interface methods:
function speak(str):String
}
And then I'm trying to load it:
public function SWFLoader()
{
var url='http://xxxxxxxx/test.swf';
var loadURL:URLRequest=new URLRequest(url);
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
var context:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain);
loader.load(loadURL, context);
}
private function completeHandler(event:Event):void
{
var test:ITest;
test = event.target.content as ITest;
test.speak("ggg");
}
So if I have test.swf in the same directory(local way) it work's fine. But if I'm placing it on the dedicated server: (event.target.content as ITest) returns null. However, I can access speak() without interface like this event.target.content.speak("a!");
How to solve this problem?

try this:
var test:ITest = ITest(event.target.content );
http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7f87.html

How do you share the ITest interface between your two swf ?
I imagine you have two projects one for the test.swf (the loaded one) and one for the loader (I'll call him loader.swf). I think you can't just declare the ITest interface twice (one for test.swf, one for loader.swf). If you do so, there will be two interfaces, with the same interface name, the same declared methods, but they still will be 2 different interfaces. And casting one into another will fail.
I bet that if you do (as suggested by PatrickS)
var test:ITest = ITest(event.target.content );
You will see a type error -> that's the advantage of this form of casting. This will confirm what I think : the two interfaces are different.
To really share the interface between your 2 projects, you should store it into a library (.swc file) and use that library in your 2 projects. This should solve the issue.

Related

as3 Call function in document class from child swf

I have a loader swf acting as the main swf that is responsible for loading and rendering external swf's.
In the document class of the loader swf, I have a function named test.
public function test() {
ExternalInterface.call("console.log", "Test");
}
I want to call this function from the child swf that is being loaded in using an external class known as StateManager. A new instance of the StateManager class is being created in the document class of the loader swf as can be seen below.
import com.xxxx.state.StateManager;
public class Loader extends MovieClip {
private static var _instance:Loader;
public static function get instance() { return _instance; }
public var stateManager = new StateManager();
// Other code has been ommited obviously.
}
A function is then called in StateManager which renders the new swf.
public function setActiveState(url) {
var request = new URLRequest(url);
var loader = new Loader();
loader.load(request);
addChild(loader);
}
In the child swf's document class, I have attempted to call the loader swf's test function using many different methods, all of which have resulted in nothing happening and no error being produced (I have confirmed that the child swf is rendering properly). I have tried using the following code.
public class ChildSWF extends MovieClip {
public function ChildSWF() {
MovieClip(parent.parent).Loader.instance.test();
}
}
As well as
public class ChildSWF extends MovieClip {
public function ChildSWF() {
MovieClip(parent.parent.parent).Loader.instance.test();
}
}
and many other pieces of code that I have seen when researching this problem. If anyone could help, that would be greatly appreciated.
First. Never, absolutely never name your classes as the already existing classes. You're, like, welcoming future troubles with the huge neon WELCOME display with the occasional firework blasts in the background.
Then. Your class Loader is not a member (nor a variable) of any display object and just cannot be accessed the way you try it. Classes do not work like that. They are definitions of the ApplicationDomain. You might want to find and read about it: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/system/ApplicationDomain.html#getDefinition()
The rest is pretty simple.
public var callBack:Function;
public function setActiveState(url, handler)
{
callBack = handler;
var request = new URLRequest(url);
var loader = new Loader;
loader.load(request);
addChild(loader);
}
Then in the loaded content:
public class ChildSWF extends MovieClip
{
public function ChildSWF()
{
(parent.parent as Object).callBack();
}
}
The loaded content will call whatever method reference you will have in the callBack variable;

AS3 Accessing a class property that relies on URLLoader

I'm facing some problems in AS3. For example, I have two classes Car.as and ReadXML.as as follows:
Car.as
public class Car{
public function get price():String{
var priceXML:ReadXML = new ReadXML('price.xml');
return priceXML.file;
}
}
ReadXML.as
public class ReadXML{
public var file:XML;
public var loader:URLLoader;
public function ReadXML(fileName:String):void{
loader = new URLLoader();
loader.addEventListener(Event.COMPLETE, _loadComplete);
loader.load(new URLRequest(fileName));
}
private function _loadComplete(e:Event):void{
file = new XML(loader.data);
loader.removeEventListener(Event.COMPLETE, _loadComplete);
}
}
But when I try to access the price property,
var carObj:car = new Car();
trace(carObj.price)
it returns null which I presume is because the URLLoader hasn't been finished. So what is an alternative or solution to this? Thanks!
I think loading an XML file every time you want to check an instance's 'price' property is the problem.
I'd recommend loading the XML file as part of your application's initialisation, and including the _loadComplete function as part of that initialisation; When the XML is loaded, your application can then continue and instantiate as many 'new Car()'s as it fancies - no delay will be required if the XML is pre-loaded.

How to return a variable from an actionscript Event? Loading XML file

i'm trying to load an xml file from my assets folder.
I wrote this function :
public static function loadXML(i_fileURL:String):XML // i want to return the actual loaded xml here
{
var xml:XML;
var ldr:URLLoader = new URLLoader();
var request:URLRequest = new URLRequest(i_fileURL);
ldr.addEventListener(Event.COMPLETE, onXMLLoad);
ldr.load(request);
//how can i return the loaded xml?
}
public static function onXMLLoad(e:Event):void
{
var ldr:URLLoader = URLLoader(e.target);
var myxml:XML = new XML(ldr.data);
trace(myxml.toXMLString());
//how can i return myxml to loadXML function?
}
Is there a different way to do this?
Thank you!
You can do something like a promise or future, where you return empty XML and then populate it with the actual XML when the call returns. Since you are using Flex, you have access to data binding, which should allow this approach to work just fine.
Note that you really shouldn't be using static methods for this, and your onXMLLoad member has no reason to be exposed. Here's what the updated code might look like:
package service {
public class XMLLoader {
//note that the existence of this variable means that you need
//to create a new instance of the Class each time you make a call.
protected var future:XML;
protected var _url:String;
public function loadXML(url:String):XML {
_url = url;
var request:URLRequest = new URLRequest(url);
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.Complete, onLoad);
loader.addEventListener(IoErrorEvent.IO_Error, onFail);
loader.addEventListener(SecurityErrorEvent.Security_Error, onFail);
future = ;
return future;
}
protected function onLoad(e:Event):void {
var loader:URLLoader = e.currentTarget as URLLoader;
var data:XML = loader.data as XML;
if (data) {
//you lose your original root node, because you want data
//binding to fire on the future object you returned.
future.setChildren(data.children());
}
}
protected function onFail(e:Event):void {
//both Security and IOerrors have a text property, but they
//can't both be cast to the same thing.
trace('failed to load', _url, e[text]);
}
}
}
One thing to be aware of with this method is that you need to keep a reference to the instance around until the data has updated, or else it could be garbage collected before it populates the future. Because of that, you're probably better off following the conventional approach of having your instance dispatch a custom event that carries the data that it was retrieving. If you want an example of that, post back and I can provide you an example.
you can't. because xml load request is asynchronous. when you called loadXML, onXMLLoad not yet arrived. so such work impossible asynchronous return. surely you can waiting the function process while loop using, but this method not good. because to full use a cpu resource, overkill. you must next process in onXMLLoad function. It's the most appropriate. or xml variable declared as global, and using a ENTER_FRAME or TimerEvent as a way to continue to operate if the xml is not null.
Since the URLLoader is asynchronous, it's not safe to create a static loader function as it would be quiet easy to mix up returned data during multiple calls. Even if you attempted to accomplish what you want with the use of Event.OPEN and a vector of URLs to keep track of the which completed data should belong to each URL, asynchronousity works on a first-come, first-served basis so it wouldn't be possible to have persistent alignment of the file URL and the returned data.
I suggest that you create instances of an XMLLoader class that uses a custom XMLLoaderEvent, which will return both the xml data and the associated file URL. The following code is untested, but with possible typos aside, it should work as intended.
Use Case
var xmlLoader:XMLLoader = new XMLLoader();
xmlLoader.addEventListener(XMLLoaderEvent.COMPLETE, xmlLoadCompleteEventHandler);
xmlLoader.load("myXMLFile.xml");
function xmlLoadCompleteEventHandler(event:XMLLoaderEvent):void
{
xmlLoader.removeEventListener(XMLLoaderEvent.COMPLETE, xmlLoadCompleteEventHandler);
trace(event.type, event.fileURL, event.xml);
}
XMLLoader.as
package
{
//Imports
import flash.events.EventDispatcher;
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLRequest;
//Class
public class XMLLoader extends EventDispatcher
{
//Properties
private var loader:URLLoader;
private var fileURL:String;
//Constructor
public function XMLLoader():void
{
loader = new URLLoader();
loader.addEventListener(Event.COMPLETE, loadCompleteEventHandler);
}
//Load
public function load(fileURL:String):void
{
this.fileURL = fileURL;
loader.load(new URLRequest(fileURL));
}
//Load Complete Event Hanlder
private function loadCompleteEventHandler(event:Event):void
{
loader.removeEventListener(Event.COMPLETE, loadCompleteEventHandler);
dispatchEvent(new XMLLoaderEvent(XMLLoaderEvent.COMPLETE, fileURL, XML(loader.data)));
}
}
}
XMLLoaderEvent.as
package
{
//Imports
import flash.events.Event;
//Class
public class XMLLoaderEvent extends Event
{
//Constants
public static const COMPLETE:String = "complete";
//Properties
public var xml:XML;
public var fileURL:String;
//Constructor
public function XMLLoaderEvent(type:String, fileURL:String = null, xml:XML = null)
{
super(type);
this.xml = xml;
this.fileURL = fileURL;
}
//Clone
public override function clone():Event
{
return new XMLLoaderEvent(type, fileURL, xml);
}
//To String
public override function toString():String
{
return formatToString("XMLLoaderEvent", "type", "fileURL", "xml");
}
}
}

How to Make Popup window as Global in Flex?

Actually in my Flex Application have Some Popup windows and i want take some values in this Popup Window But The Values are Comming NULL
So how to Make a PopUp Window as Global? Because we are Using the values Globally.
Please Give Suggestion...
Edit
I'm Edit with some code...
Main.mxml(Main Aplication), Demo1.mxml(PopUpWindow), Demo2.mxml(PopUpWindow)
Now in Demo1.mxml have variable like...
[Bindable]private var arrayC:ArrayCollection=new ArrayCollection();//Hear Some value their.
NOw i want Use arrayC in Demo2.mxml then ..
public var variable1:Demo1=new Demo1();
var ac:ArrayCollection = new ArrayCollection();
ac = variable1.arrayC;
But hear ac contain Null Value Why?
Then,Now i'm Thinking Demo2.mxml(PopUpWindow) is Converting To Global Scope so it's value Used in Any Where .
Null because of you are tried create new instance so that each instance having their own state.
Also i bet you can't access arrayC ArrayCollection variable declared as private so you can't acccess.
Need to follow few steps
[Bindable]public var arrayC:ArrayCollection=new ArrayCollection(); //Make public variable
Use Singleton Class for you application
package com.foo.bar {
public class Model {
private static var instance : Model;
public function Model( enforcer : SingletonEnforcer ) {}
public static function getInstance() : Model {
if (!instance) {
instance = new Model( new SingletonEnforcer() );
}
return instance;
}
public var arrayC:ArrayCollection = new ArrayCollection();
}
}
class SingletonEnforcer{}
For more details Singleton pattern
private var popup:Demo1;
popup = PopUpManager.createPopUp(this,Demo1,true) as Demo1;
popup.arrayC = Model.getInstance().arrayC; // Here set value from Model class
PopUpManager.centerPopUp(popup);
Suppose you tried to access demo1.mxml arrayC variable in Demo2.mxml
var demo1_arrayC = Model.getInstance().arrayC;
Note that you can access arrayC arraycollection anywhere in your application like Demo2.mxml,Demo3...etc.
But better we have to avoid Singleton Class (unit test diffcult ..etc).
If you are using the values Globally, then no matter what you mean by the "Make a PopUp Window as Global", I strongly suspect that you would be best served by a singleton event dispatcher.
package com.example.demo.models {
import flash.events.IEventDispatcher;
import flash.events.EventDispatcher;
[Bindable]
class MyGlobalStuff extends EventDispatcher {
public var someGlobalValue:*;
private var _instance:MyGlobalStuff;
public function MyGlobalStuff (lock:SingletonLock, target:IEventDispatcher=null) {
super(target);
if(!(lock is SingletonLock)) {
throw(new Error("MyGlobalStuff is a singleton, please do not make foreign instances of it"));
}
}
public static function getInstance():MyGlobalStuff {
if(!_instance) {
_instance = new MyGlobalStuff (new SingletonLock());
}
return _instance;
}
}
}
class SingletonLock{}
The idea is this: that you would bind in your popup to
{myStuffModel.someGlobalValue}
myStuffModel would be initialized in your mxml as:
protected var myStuffModel:MyStuffModel = MyStuffModel.getInstance();
then in any other class throughout your application you can bind to or access the EXACT same data via the singleton model.

as3 declaring a GLOBAL variable - in TIMELINE / outside of CLASS

I am looking to declare a GLOBAL VAR in the main time line.
Then I need to access that GLOBAL VAR from another externally loaded SWF's.
QUESTIONS:
How do I create the global var in the main timeline?
How do I access that var in externally loaded swf files?
First, you shouldn't use any global/static state. In your situation this is even more true, because Singletons are a royal pain in the butt across different applicationDomains.
Instead, you should use something called Dependency Injection. Think of your little swfs as starving orphans. When they have loaded, they don't run up to your main swf and pick its pockets. Instead, the main swf magnanimously presses money into their little hands.
So, how do we make this happen? One way is that we could compile a reference to their Document class(es) into the main swf, and then we could set a variable that the Class exposes. However, this can get pretty heavy and isn't really necessary.
Instead, you can write something called an Interface, which defines the "idea" of an orphan.
It might look something like this:
public interface IOrphan {
function get alms():Number;
function set alms(value:Number):void;
}
Note that you have to use getters and setters with Interfaces, because you can't use them to define vanilla variables. However, that's going to work out great for our actual Orphan:
public class Oliver implements IOrphan {
private var _alms:Number;
private var _totalAlms:Number;
public var tf:TextField;//put this on stage and allow Flash to populate automatically
public function get alms():Number {
return _alms;
}
public function set alms (value:Number):void {
_alms = value;
_totalAlms += _alms;
updateAlmsMessage();
}
private function updateAlmsMessage():void {
tf.text = 'That was a donation of ' + _alms + '.\n'
'I now have ' _totalAlms + '.\n'
'Please, sir, can I have some more?';
}
}
Now, all you need to do is populate that variable on load. There are several ways you can do this, such as watching the stage for IOlivers to be loaded, or you could be more direct about it:
private function loadSwf(url:String):void {
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
var request:URLRequest = new URLRequest(url);
loader.load(request);
addChild(loader);
}
private function completeHandler(e:Event):void {
((e.target as LoaderInfo).content as IOrphan).alms = .25;
}
If these are variables that you only want to set once and will never change, you can just create a class that holds static constants.
package
{
public class Env
{
public static const WHATEVER:String = "Whatever!";
public function Env()
{}
}
}
Then you could access them later in your program like so:
trace(Env.WHATEVER);
However, if you want global variables that can change, I like to handle this by using a singleton class.
package
{
import flash.events.EventDispatcher;
public class Control extends EventDispatcher
{
//---------------------------------------
// PRIVATE & PROTECTED INSTANCE VARIABLES
//---------------------------------------
private static var _instance:Control;
//---------------------------------------
// PUBLIC VARIABLES
//---------------------------------------
public var whatever:String = "Whatever";
//---------------------------------------
// PUBLIC METHODS
//---------------------------------------
public static function get instance():Control
{
return initialize();
}
public static function initialize():Control
{
if (_instance == null)
{
_instance = new Control();
}
return _instance;
}
//---------------------------------------
// CONSTRUCTOR
//---------------------------------------
public function Control()
{
super();
if (_instance != null)
{
throw new Error("Error:Control already initialised.");
}
if (_instance == null)
{
_instance = this;
}
}
}
}
The difference here is that you need to grab the instance of your singleton before you can get to what's inside it. It'd look a little bit like this.
private var _control:Control = Control.instance;
// Reading a global variable
trace(_control.whatever);
// Change a global variable
_control.whatever = "Foobar!";
So whenever you change "whatever", that variable will change for all loaded SWFs. If you want to be really fancy about it, you could use getters/setters in your singleton rather than simple public variables.