TypeError: Error #1006: value is not a function

Another tip: if you get this error, one possible explanation is that you have tried to declare a variable with the same name as an already declared function – perhaps one which has been inherited from a superclass.

ProgressEvent.PROGRESS misreports bytesLoaded & bytesTotal

One problem you might run into involves ProgressEvent.PROGRESS events seeming to misreport the proportion of the file that has loaded.

This would cause a preloader’s bar to extend beyond the 100% mark. We don’t have time currently to outline the full technical context of the issue, but did spend some time examining it, and we solved it.

The solution to the problem was not to use the bytesLoaded and bytesTotal of the actual ProgressEvent in the event listener, but to instead use the properties of the target (which is a LoaderInfo object). So your code looks like this:

private function update(e:ProgressEvent):void
{
  // causes misreport:
  // var bt:uint = e.bytesTotal;
  // var bl:uint = e.bytesLoaded;

  // prevents misreport:
  var bt:uint = e.target.bytesTotal;
  var bl:uint = e.target.bytesLoaded;

  bar.scaleX = bl/bt;
}

We’ll try to expand on this issue at a later time.

Detecting onReleaseOutside in AS3

ActionScript 2.0 has support for the onReleaseOutside event in the following manner:

myMovieClip.onRelease =
myMovieClip.onReleaseOutside = function():Void
{
   this._x += 300;
}

This directly applied event handler will trigger when the mouse is released over myMovieClip or when that clip is clicked upon then the mouse is subsequently released elsewhere.

ActionScript 3.0, however, does not define an onReleaseOutside event type, though there are plenty of other MouseEvent types.

Usually, this is not a problem. You want to detect a CLICK event, which is dispatched when the user has pressed the mouse down then released it over the same object (with any number of other possible mouse events in between). The logic for this is that the user might have changed their mind and be deliberately releasing the mouse while not over the object, not wishing to trigger any event.

But suppose we are creating a button which reacts to a MouseEvent.MOUSE_DOWN event – perhaps a fast-forward button such as we created recently in order to speed up the playback of an MP3. In this case, we want the MP3 to revert to normal playback speed even if the user releases their mouse while not exactly over the button (as is often the case). We need a releaseOutside event for this eventuality.

So how are you supposed to detect when the user has clicked on your interactive object then released the mouse outside? The solution is to temporarily apply a new event listener until the mouse is released, as follows:

private function mouseDown(e:MouseEvent = null):void
{
   stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp, false, 0, true);
}

private function mouseUp(e:MouseEvent = null):void
{
   stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUp);
   // do other stuff
}

myButton.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown, false, 0, true);

This code is minimal, but it illustrates the point. We always detect for a MOUSE_DOWN on the given object (myButton), but only when this has occurred do we then listen out for a MOUSE_UP. When this happens (regardless of where) our other listener function is triggered. Note that this then unsubscribes itself from the Stage, and then everything is cleaned up.

Manually triggering event listener functions

ActionScript 3.0 was designed to provide much better error handling than its precessor, with both run-time and compile-time checks being made. Yet although the language is stricter in some senses, it also provides new, considerable, flexibility. For example:

  1. The rest... parameter, which enables a function to receive any number of comma-delimited arguments.
  2. The ability to set default parameters for function arguments.

These two features can prove to be extremely useful.

Another place where you run into ActionScript 3.0’s pedantry is in dealing with event handlers. Event handlers must be declared such that they are equipped to (naturally) handle an event. For example:

private function init(e:Event):void
{
  fadeIn();
  trace(this + "initialised");
}

We tend to trigger init methods when an object is added to the display list. So we subscribe the listener function as follows inside our constructor function:

addEventListener(Event.ADDED_TO_STAGE, init, false, 0, true);

This is all well and good, and if the listener is triggered without a valid Event object being sent to it, Flash will produce an error (part of the strict error checking). But what if, occasionally, we did want to trigger a function which is configured to be an event handler, but trigger it manually (i.e. not on the generation of an event)?

We have the required e:Event parameter to deal with. (Not also, incidentally, that all other Event object types extend the base Event type, so you can get away with typing the required object simply as Event, for flexibility.)

We have a number options here. One is to use the event listener as a merely a proxy when we define it, so it in turn calls another function:

private function initListener(e:Event):void
{
  init();
}

private function init():void
{
  fadeIn();
  trace(this + "initialised");
}
...
addEventListener(Event.ADDED_TO_STAGE, initListener, false, 0, true);
...

This leaves us free to call the init() method whenever we want then – it would not have to be (or be able to be) triggered on an event’s dispatch. This is fine, however it seems rather verbose. It means we have to write, theoretically, twice as meny functions!

Another option is we can send a “dummy” event to our listener method whenever we want to manually call it:

private function init(e:Event):void
{
  fadeIn();
  trace(this + "initialised");
}
...
init(new Event(Event.ADDED_TO_STAGE));

This works, but it seems messy to be faking events.

The third option takes us back to the beginning of this article, and the topic of default values for function parameters:

private function init(e:Event = null):void
{
  fadeIn();
  trace(this + "initialised");
}
...
init(new Event(Event.ADDED_TO_STAGE));

Because it is possible to supply default values, we can avoid an argument mismatch error but specifying that if no event object is actually sent to the listener, that parameter should be defined as null.

While some may say this violates AS3’s tight security, it is currently our preferred solution to this issue. You might find it the best way to go too. Remember that inside the body of the event handler you can always check to see if event parameter “e” is defined and, if so, what kind of event it is. You can also surround certain attempts by try... catch... finally clauses to avoid your whole application breaking.

We always define event handlers with the event parameter set to null, and – of course – we add them with weak references.

ADDED_TO_STAGE event fires twice

Display objects often need to perform set-up tasks which depend on the stage. They might wish to access stage.stageWidth or stage.stageHeight, for example. The trouble is, the stage property will return null until that object is on the Display List.

The standard way around this is to put such set-up tasks in an init method, which you then trigger separately:

private var _box:Box;
_box = new Box();
addChild(_box);
_box.init();

So the init method is triggered once the object is added to the Display List. This works fine. The only downside is that the object cannot initialise itself. This solution seems slightly clumsy from an OOP point of view also a little verbose. Could the object not auto-trigger its own init method once it is on the Display List?

Not until Flash Player 9.0.28.0, which added support for the ADDED_TO_STAGE event, used as follows:

// constructor
public function Box():void
{
   addEventListener(Event.ADDED_TO_STAGE, init);
}

public function init(e:Event):void
{
   // code dependent on stage property
   y = stage.stageHeight-100;
}

The trouble is, however, this event erroneously fires not only for the given item, but also when its parents are added to the Display List. This runs your init method multiple times, possibly causing problems.

This issue is a Flash Player bug known to Adobe. Read more about the ADDED_TO_STAGE event firing twice issue in the official bug report entry. A workaround with a sample class may be found there. We use that workaround inherited from a superclass for all our display objects, and until the issue is solved we suggest you either use it too, or use the init method solution when set-up code depends upon the stage.