What is the correct way to add components to the library of a Swf? - actionscript-3

I've been having a problem that's plagued me many times in the course of developing a Flash project. It looks something like this:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at fl.containers::BaseScrollPane/fl.containers:BaseScrollPane::drawBackground()
at fl.controls::TileList/fl.controls:TileList::draw()
at fl.core::UIComponent/::callLaterDispatcher()
TypeError: Error #2007: Parameter child must be non-null.
at flash.display::DisplayObjectContainer/addChildAt()
at fl.controls::BaseButton/fl.controls:BaseButton::drawBackground()
at fl.controls::BaseButton/fl.controls:BaseButton::draw()
at fl.core::UIComponent/drawNow()
at fl.controls::ScrollBar/fl.controls:ScrollBar::draw()
at fl.core::UIComponent/::callLaterDispatcher()
Now, in my case, this error stems from initializing components in code when they have not been explicitly added to the fla's component library in CS4. In the past, I have run into this issue when trying to dynamically create ScrollPanes in code. I have solved it by adding ScrollPane components to my Main.fla's library. This seemed to work for a while.
Now, I am trying to use an AstraFlash AutoComplete box. I have imported the proper fla files into CS4, and placed an AutoComplete box into my Swf. Everything builds fine, but the above error occurs when the Swf is loaded. My thought is that the AutoComplete box is trying to create a ScrollPane as part of its functionality. Ok, I understand this, so I add the ScrollPane component to the library as well with the same results.
Usually I would just mess with the library components/settings until I get rid of the error, but I'm sick of running into this, and I want to know the correct way to solve the problem. So, here are a few questions I have:
When are you required to add a component to a Fla's library rather than just creating the component in code?
Which Flas do you need to add the component to? Just the one using it? Or all of parents of that Fla as well?
Let's say the Autocomplete component requires a ScrollPane component. Why isn't this dependency recognized when I add the one component? Why must I explicitly add it?
What is the difference between adding a component to the library, and adding it to the library's 'Component Assets' folder? What is this folder's purpose?
I really need this AutoComplete component to work. Assuming the AS3 code is correct, and I am still getting the above error, what settings do you think are probably incorrect? Out of frustration, I have tried adding every possible component to the library, as well as to the library's component assets folder just to have a starting point, but I still get the error.
Any help is appreciated.

I'm not sure I understand you're setup. What I'm assuming is you have a child fla that contains some components and you need to create instances of those components in a parent(loader) fla.
It should work if you compile the classes from the child fla into the parent fla, but that would duplicate things.
The issue is when you load a swf, the classes sit in a different ApplicationDomain.
Simply put, that's the thing that manages classes in a swf so you don't have class collisions between a loader and loaded swf and some other security stuff.
I made a simple fla that holds a Button component(fl.controls.Button) and loaded that from a loader fla. I didn't add the Button component to the loader fla, but did create a button instance, using the loaded swf's application domain. Here's how:
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaded);
loader.load(new URLRequest('componentContainer.swf'));
function loaded(event:Event):void {
addChild(loader.content);
var SWFButton:Class = loader.contentLoaderInfo.applicationDomain.getDefinition('fl.controls.Button') as Class;
var button = new SWFButton();
button.label = 'Test';
addChild(button);
}
There is a page in Programming Actionscript 3.0 about thise kind of issues and how to use ApplicationDomain, but I didn't fully understand it to be honest.
HTH,
George

Related

Actionscript 3 - Accessing a variable on the main timeline

I'm trying to make a file that is easy for a non-flash user to use/reuse to easily display content. The key here is that this file is to be a template for a novice user to just copy/paste some very minimal code to create different "flash card" type swf files.
The file I am creating has multiple buttons on the main timeline which when clicked, attaches a movie clip which will display a dynamic text area with content specific for the button that was clicked. The content for the text area will be loaded from a separate text file.
For the sake of this example, I'm just going to refer to one button...
So, on the main timeline, in frame 1, I have a variable definition:
var myFilename1:String = "mySampleFile2.txt";
When the button on the main timeline, in frame 1 is pressed, a movie clip is loaded which contains a text area. The content for the text area is located in that file: mySampleFile2.txt.
If I hard-code the file name, it works like a dream:
myTextLoader.load(new URLRequest("mySampleFile2.txt"));
But I don't want to hard code the file name. I want to refer the variable in the main timeline. In AS 2, it would have been
myTextLoader.load(new URLRequest(_root.myFilename1));
In AS3 I thought it would be either:
myTextLoader.load(new URLRequest(root.myFilename1));
OR
myTextLoader.load(new URLRequest(MovieClip(this.parent.root).myFilename1));
When I run the code I get the following error and when I run a trace I get the file name is NULL.
TypeError: Error #2007: Parameter url must be non-null.
How to I access the file name stored in the variable on the main timeline?
*************************** UPDATE! *************************
So I just discovered that the issue is related to a button on the screen. The button is one from the buttons library. If I remove the button, everything works great. But as soon as that button is on the main timeline, it makes it to I cannot access the variables using MovieClip(root).variable_name;. Unfortunately I want that button to trigger the events within the MovieClip. Any thoughts?
Not a good idea
You are not able to achieve your goals with this bad practice approach.
to use/reuse
The code you want to provide is not very reusable. It heavily relies on one variable existing in a certain place. Therefore it cannot be use twice in a project.
But I don't want to hard code the file name.
And now you are hard coding the variable and its location. If you considered hard coding the file name to be a bad things, consider this a bad thing, too.
What the problem is
Basically speaking, the problem is that your component is reaching out to grab this variable from somewhere within your project. But it is not the concern of the component to find the content it should display. It is not well encapsulated.
Learning from existing things
You want to display text. Let's take a look at the TextField class to see how it displays text.
var tf:TextField = new TextField();
tf.text = "hello";
addChild(tf);
As you can see, the text that it should display is passed to the TextField object. There is not some arbitrary variable one has to set in order to modify the text, as you are planning to do:
var tf:TextField = new TextField();
var someArbitraryVariableThatModifiesATextField = "hello";
addChild(tf);
There is no obvious connection to the TextField object and if there's a second TextField, this doesn't work at all.
Applying that to the problem at hand
Just like the TextField, your "flash card" should receive the file as a parameter. Either pass it to the constructor as seen in the example below, or create a method that takes it as a parameter.
var card:Card = new Card("mySampleFile2.txt");
addChild(card);
Additional thoughts
Create additional methods to set the values individually. There's nothing worse than some code that does exactly what one wants, but only operates on files and one doesn't have a file. The goal is again, to make it easy to reuse the code
Use the [Inspectable] meta tag to allow the user of your code to modify the properties at author time. This can be used to the extend of modifying properties belonging to a physics engine, now this is what I would call easy to use for a novice user.
Instead of writing code and thus requiring to recompile the file again, take the information (either the path to the file or it content) from the flashars that are passed to the .swf file when it is embedded into an html page. This makes the single .swf file truely reusable and easiest to use, because there's no As3 coding required whatsoever.
I haven't tested this but I believe the "root"-stage would be:
this.parent
In the child swf.
check out this question: as3 access variable from parent swf
Good luck!
Accessing variables or movieclips at main timeline is as following:
AS2:
_root.variable_name;
AS3:
MovieClip(root).variable_name;

AS3 Load External SWF with googleMap component inside, why compiler raise error to null object pointer?

I'll try to be short, because I guess this problem is related to the use of the googleMap component inside Flash IDE.
I have a swf file compiled with a googleMap component inside, and by itself it works great.
Problem raises whe i try to load it into another Swf file, adding it to as a child of a Movieclip.
If, with the same loader code i try to load another simple swf, I have no problems.
So I'm pretty sure the problem is related to this particular swf that uses googleMap component.
As my first Idea to solve this I tryed to add the googleMapsLibraryComponent, draggin it inside the MovieClip was supposed to load this external ggMap swf file. But nothing still have
a message Error #1009 tryin to access a property or method of a null object, inside the constructor of the base class of the child external swf.
Sub question #2:
Also, how is it possible to debug such a situation? Since I'm dealing with a compiled swf? no chance but to debug them separately?
many thanks in advance...

Link symbol from loaded swf to custom class dynamically

I have a project where I load an external file with asset symbols (assets.swf) into the main swf and then add the symbols to the display when needed. I want the classes associated with each symbol to be linked to a custom class at runtime in the document class. I'd really like to avoid defining the custom classes in the assets fla through the symbol properties.
In AS2, this was possible with Object.registerClass as below:
Object.registerClass("assetID",AssetClass);
this.attachMovie("assetID", "asset_mc", 0);
So the symbol was independent of the class it is linked to at runtime.
In AS3, I'm seeing references to registerClassAlias but there is very little reliable documentation of it available online.
Does anyone know of a way of doing what I'd like to do with registerClassAlias or any other way?
thanks!!!
matt
First, you need to load your asset symbol and keep a reference to the loader.
assetsLoader.load(new URLRequest("assets.swf"));
When the loading is done you can retrieve your assets within the loaded SWF ApplicationDomain.
var assetClass:Class = assetsLoader.contentLoaderInfo.applicationDomain.getDefinition("MyAssetClass") as Class;
var asset:* = new assetClass();
Note: MyAssetClass should be defined inside assets.swf!
If you want further informations, you can read this article.

Loading and using SWF files

I'm new to AS3, and am trying to understand how externally loaded SWFs work in AS3. Since Flash 4/5, it was common to have one main SWF file in a Flash web project, and then load other SWF files into it, often for various "sections" of a website or web project. In the main file, we'd have masks animating the container movieclip(in which external sections/SWF files were loaded) and have animations and transitions play as the section finished loading and the loaded content was displayed.
In AS3, I've used the Loader class to load and display the external file, my main problem is in communicating with the loaded content, call it's functions, or call root functions from it.
In AS2, we could use someMovieClip.loadMovie("ExternalContent.swf") and the ExternalContent file would load inside someMovieClip. You could access functions on the "External.swf" main timeline using someMovieClip.function();. And inside the "ExternalContent.swf", we could use _root.function() to access functions in the main file ExternalContent was being loaded into. Doing this in AS3 seems bizarre and neurotic, and I feel like I'm missing something fairly basic here.
//Loading in ExternalContent.swf into the sprite
//ExternalContent has a movieclip called "boxes" on it's main timeline
//boxes has a boxesPrompt() function in it's timeline.
var sprite:Sprite = new Sprite();
addChild(sprite);
var loader:Loader = new Loader();
loader.load(new URLRequest("ExternalContent.swf"));
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,onLoaded);
function onLoaded(event:Event):void
{
sprite.addChild(event.target.content);
sprite.boxes.boxesPrompt();
//Flash gives the following compiler error at the above
//Scene 1, Layer 'Layer 1', Frame 1, Line 21 1119: Access of possibly undefined property boxes through a reference with static type flash.display:Sprite.
//But when I comment out sprite.boxes.boxesPrompt() and use this, it works:
event.target.content.boxes.boxesPrompt()
}
The boxesPrompt() function inside the "ExternalContent.swf" just traces it's parent, grand-parent, and great grand-parent - trace(this.parent.parent.parent);. And when I call that function inside the onLoaded event-handler using "event.target.content.boxes.boxesPrompt()", it shows that the Boxes object(which was on the main timeline of External.SWF), has a parent movieclip, a grand-parent sprite, and a great grand-parent object mainTimeline.
I thought re-parenting the loaded content into the sprite would allow me to access the loaded content as easily as loadMovie() used to be - accessing loaded content like it was present directly inside the clip it was loaded in. But that doesn't work at all.
So to rephrase, my question is:
How do I communicate from the main "loader" SWF file, with the content that's loaded in. I don't want to communicate using event.target.content.{etc} because then I'd only be able to address the loaded content inside the Loader's event.complete event handler.
How do I "re-parent" loaded content, so I can place it inside some movieclip/sprite on the main timeline of the loader file, rather than using some really long convoluted way.
How to communicate from inside the loaded content, to the main/loader file. Previously, we'd use _root.functionName() to do stuff like play some animation transitioning from the current externally loaded "section" to another section. How'd I go about doing that.
AS2 & AS3 is vastly different. But you will have to swallow the fact that AS3 has been developed as an improvement over AS2. So any transition you make, is also for the better.
For eg : The _root in AS2 allowed global objects & variables to accessed & changed anywhere, which is a bad practice & leads to non maintainable code in a project.
Having said that, let me address your questions:
If you are able to get access to the loaded content with
event.target.content... you should save it inside a,say class
variable & may access it later elsewhere in the class.
You must understand that you will be able to access the content only
after loading it, so have to wait for it to complete anyway &
event.complete handler is probably your best bet.
I doubt if you can pick random content from a loaded swf & re-parent it into the current swf.As explained you might not have a long convoluted way.
Accessing the parent could be done in many ways. You can use .parent or actually call a function from the parent swf passing its reference to the child.
var sprite;
addChild(sprite);
var loader:Loader = new Loader();
loader.load(new URLRequest("ExternalContent.swf"));
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,onLoaded);
function onLoaded(event:Event):void
{
sprite = event.target.content;
//This should work
sprite.boxes.boxesPrompt();
}
See this example for more info.

AS3 Problem in loading external SWF into Loader

I have main application that loads external swf's through the Loader Component. But some swf's that are working well on their own don't load into the main app. When I tried to load one of that swf's from fla of main app it gave error that it's looking for some classes. By the name of this classes it looks like it were parts of loaded swf but as swf that is already compiled and working well why is it looking for this class when it's trying to be loaded by the main app?
I didn't find anything that would refer to this kind of issue. Any help will be highly appreciated.
It seems like you got an application domain collision. This can happen if you got conflicting class names in each SWF (e.g swf1 has a class named Main, swf2 has a class named Main as well).
To fix that, load the SWFs into a new application domain:
loader.load(new URLRequest("g.swf"), new LoaderContext(false, new ApplicationDomain(ApplicationDomain.currentDomain)));
If it's not that, you most likely have some code on the first frame of the movie that executes on initialisation of the SWF (See if you get Event.INIT before you get Event.COMPLETE).
This can be easily fixed by removing the code from the frame.
Just for checking I made fla file that contained only Loader component and code of loading:
var loader:Loader = new Loader();
addChild(loader);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadingFunc);
loader.load(new URLRequest("g.swf"));
function loadingFunc(event:Event):void{
var li:LoaderInfo = event.target as LoaderInfo;
var mc:MovieClip = MovieClip(li.content)
}
This code is from the testing file.
But even this way it still looking for some class that seems to be one of external loaded swf.
The error is such:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at src::Dedo()
at src::Main()
I have no such classes in my main app. So it could be only classes from external swf.