bgx:components logo
© 2004 -2005
Bernhard Gaul



scaleContent Fix for the the Macromedia Loader Component
Flash MX 2004 v.7.0 and 7.2

The Problem

As you may have seen I use examples of MovieClips containing the Macromedia Loader component for my Bgx Flexible List Component and struggle since quite a while with the fact that in particular using Internet Explorer the loaded content is not scaled even though scaleContent is set to true.

I have now made an effort to track down exactly what happens and found out that the component starts checking the load progress by initially setting the variable that stores the _totalBytes of the file to load to -1.

When checking load progress it then checks first 3 times if that property is still -1 (instead of 0) which basically means loading hasn't started yet.

If after 3 checks the value is still -1 the component aborts checking for load progress, dispatching the complete event without actual check if the file has been loaded or not. In turn that means that scaling will be attempted before the content is loaded, once it arrives it doesn't get scaled anymore.
[If you want to check the details see around line 117 in the file mx.controls.ExternalContent.as, where it says if (x.failedOnce > 3) as part of the checkLoadProgress() function].

As I noticed it may take more than 3 loops before the actual load starts when you request many loads simultaneously like with the Flexible List examples or if you simply have a bad connection over the internet.

Solution

There are several ways of tackling the problem, however the most manageable seems to me to override the checkLoadProgress() function of the Loader component. This way everything stays intact as it is, you don't manually change pre-installed core classes (which may have unpredictable side results) and can still use the commodity of the component as-is.

The code below is a variation of the original component code found in mx.controls.ExternalContent.as, changing the hardcoded number of tries (3) to a variable maxTries that you can set at will. [Note: I am not 100% sure why you want to dispatch the complete event at all if you haven't actually loaded the file, but assuming there is a reason I left the changes at incrementing the number of checks...]

To use it either paste the code anywhere into your Flash file (e.g. at the first frame of the main timeline) before the Loader is actually used or download the BgxLoaderFix.as file (ZIP file, 2 kB) and include it using

#include "BgxLoaderFix.as"
//the following line is optional
maxTries = 560;

Clarification

As I got more than one inquiry about this here some clarifications:

Including the script once will override all Loader instances for your whole project. That includes Loader instances on any other internal timeline or even SWFs that are loaded externally. If you want to test if it works try adding     trace(maxTries + " " + this);     in the .as file just at the top of the checkProgess function. This should output the maxTries value defined wherever you included the script plus the instance path of the current Loader.

Variations

The syntax above is the one I thought gives you the least hassle, letting you define the override at startup, this being valid for your entire project and you can still use the MM component as is or simply fix existing projects by adding two lines of code.

However there are other options:

  • If you want you could define maxTries as a property of the Loader so you can adjust it for each instance, if wanted. To do so change var maxTries:Number = 500; into Loader.prototype.maxTries:Number = 500;
    Note that you also have to change if (x.failedOnce > maxTries) into if (x.failedOnce > this.maxTries); [Thanks to Dave Myron for the suggestions]
  • If you dare you can also remove the bit that dispatches the complete event alltogether, as Jeff Tapper has done in his version (see http://jeff.mxdj.com/read/1018476.htm)
  • You can create a new component subclassing the existing one, that's again the way Jeff Tapper has chosen (see http://jeff.mxdj.com/read/1018476.htm)

Rate the LoaderFix

If you liked the fix, why not go and rate it on the Flash Exchange!!

Resources

Download the BgxLoaderFix.as file
(ZIP file, 2 kB)

Example

Click the link below using Internet Explorer to load two Flash files with multiple Loader instances.

The lower one contains the Bgx Loader Fix.
I also included a trace that will show for each Loader the final value of x.failedOnce to show that it is effectively the limitation to 3 checks that causes the problem.

View the example

[Note that using Firefox I never got any entry in the traces, also with testing locally, which means loading starts immediately in these cases.]

 

History

2004-12-19: Published this page

2004-01-20: Found an alternative version on http://jeff.mxdj.com that uses a new subclass instead of overriding the component itself. Check it out.

2005-01-18: Published version 1.0.1. Fixed: delete loadList[i] >> delete this.loadList[i]

2005-04-07: The BgxLoaderFix finally gets published on the Flash Exchange. Go and rate it!!

 

Code to paste

import mx.controls.Loader;
//define the maxTries here. var maxTries:Number = 500; Loader.prototype.checkLoadProgress = function():Void { var i:String; for (i in this.loadList) { var x:Object = this.loadList[i]; //trace("loading..." + loadList[i].url); x.loaded = x.obj.getBytesLoaded(); x.total = x.obj.getBytesTotal(); //trace( x.loaded +"/"+ x.total ); if (x.total > 0) { x.obj._visible = false; this.dispatchEvent({type: "progress", target: x.obj, current: x.loaded, total: x.total}); if (x.loaded == x.total) { if (this.loadedList == undefined) this.loadedList = new Object(); this.loadedList[i] = x; delete this.loadList[i]; this.doLater(this, "contentLoaded"); } else { //NOTE BGX: also this is different than in the original code where //the call to doLater is outside the check "if (x.total > 0)" this.doLater(this, "checkLoadProgress"); } } else { if (x.total == -1) { // sometimes you get a -1 before it starts loading if (x.failedOnce != undefined) { x.failedOnce++; //NOTE BGX: the following is the line changed [orig: if (x.failedOnce > 3)] if (x.failedOnce > maxTries) { this.dispatchEvent({type: "complete", target: x.obj, current: x.loaded, total: x.total}); //trace("total == -1 loaded = " + x.loaded); delete this.loadList[i]; delete x; } } else { x.failedOnce = 0; } } //NOTE BGX: also this is different than in the original code where //the call to doLater is outside the check "if (x.total > 0)" this.doLater(this, "checkLoadProgress"); } } }

If you have any comments or suggestions please let me know at info@bgxcomponents.com.