Enabling Access to Timeline Items in AS3 after gotoAndStop()

So there’s a problem with using gotoAndStop() in AS3 classes, as soon as you call it, you temporarily lose access to items on stage (on the timeline) whether they are defined as member variables, or using getChildByName(). This is different from AS2, ite…

So there’s a problem with using gotoAndStop() in AS3 classes, as soon as you call it, you temporarily lose access to items on stage (on the timeline) whether they are defined as member variables, or using getChildByName(). This is different from AS2, items on stage were immediately accessible.

Why use the timeline at all? For one you might have a simple button using named keyframes as button states, or when dealing with assets created by designers that include animations with portions that require localisation of text. So like before you use gotoAndStop() or gotoAndPlay() to manage which “state” your MovieClip is in, but when you go to access anything on stage, it is null, even if it was on the previous keyframe. Here’s a snippet from a typical AS3 class:

Ouch, so unlike AS2, you cannot reference something on stage after a gotoAndStop()… I know! Wait a frame!? Afraid not. Waiting a frame (using a callLater or simply hooking into one ENTER_FRAME event broadcast) will not be long enough. But there is another event dispatched by Stage which might work, Event.RENDER.

I think the event sequence goes something like this:

myTitleField is defined here

gotoAndStop( “step2” );

myTextField is null here

Event.ENTER_FRAME is dispatched

myTitleField is still null here

Any code written on the keyframe itself is executed

stage’s Event.RENDER is dispatched

myTitleField is defined again!

So thanks to a tip from Senocular, the RENDER event looks like what we need. To force this event to fire, you must call stage.invalidate(), also the event is only dispatched to items on a DisplayList, and on top of that, it doesn’t go through a typical capture phase, the event is broadcast directly to the DisplayObject, but that shouldn’t matter here.

So that’s fairly crude, but the idea is there. I was speaking to Tink who suggested that we override the gotoAndStop/Play methods in a base class to automatically call stage.invalidate().

Really you want to wrap all of this up in a base class and hook it into a redraw cycle so that you don’t have to add the stage RENDER listener and handler each time you need to do this.

In my case, I have a base View class that contains some simple functionality such as a Flex-like initialization phase and callLater method. I’ve also added these overriden methods and in my case they call invalidate() on my base class, which invokes the “component-like” redraw function whenever a property is changed and it’s time to update the visuals.

My initial reason for doing this was because of shortcomings in Flash’s built in SimpleButton class, which doesn’t appear to allow for localisation or font embedding when switching states, so I ported an AS2 SimpleButton I had written.

This issue is a major annoyance as without using this workaround you are basically locking out designers from working on FLAs, and using code for everything, which isn’t always the best approach in highly creative work, it isn’t even always possible.

Anyway, I hope this proves useful, there’s a couple of other solutions out there but this one feels the most processor friendly and doesn’t rely on essentially “polling” the ADDED event, or ENTER_FRAME until your on stage element appears in memory.

Note: It’s important to remember that there are bugs related to both Event.ADDED_TO_STAGE and Event.RENDER (with wmode). So best be sure your viewers are using Flash Player 9.0.115.0 or greater to avoid a world of pain 🙂

18 thoughts on “Enabling Access to Timeline Items in AS3 after gotoAndStop()”

Yeah, it’s a major downer… I used the same approach when I first stumbled upon the problem. However, I quickly noticed that for some #%&! reason the render event is not thrown about 1/10 of the time. Huh. And this was with wmode=window. The only solution I found was to listen to the ADDED-event on the parent display object and after each event go through the display list to see whether it was fired by the display object I was waiting for…

Wow that’s really bad news. I was trying to avoid having to listen to the ADDED for each child as it would quickly become unruly. I hope this problem was not experienced in player 9.0.115.0? (Which is the version I’m going to be requiring for Flash 9 content).

Brilliant work Adobe. AS3 is sounding like a real joy for those who still use Flash and haven’t eaten that lumpy flex cool aid residue.
I can’t express how much this RIA only mind set annoys me. You are totally alienating your core demographic with this OTT “real” coding bull shite.

t listeners. While scouring the internet for a solution, I found this undocumented function addFrameScript() which allows you to apply code to a frame, in the same manner as the Actions panel in the Flash IDE. This frameScript is the *ONLY* opportunity I’ve found for executing code at the proper moment. With the above code, you can have your dynamic label with keyframes.

Heh heh. Okay, I ran myself round in so many circles looking for a solution, I somehow missed or forgot about the discussion of addFrameScript() above. So my solution is simply to apply a very light weight function call to *EVERY* frame–whether it’s a keyframe or not–to keep the custom label always applied. (I wouldn’t want to apply labels to every keyframe anyway.)

do I really have to go to frame 2
and then add a frame script on frame 1???
(in any case it doesn’t work)

AS3 is a pain in the Ass…ok it’s “powerful” but who cares!!! we want fast development here!!!…no super ultra rigid constraints!! I agree with bob: too much attention to RIA dev led adobe to forget its main target…
I am an experienced designer and programmer with a few Flash Apps on his back…i tell you: AS3 sucks! (I’m sorry to say that!)

is it possible that such a simple thing as a mc timeline and its content (that has worked for the past 8 versions) now can’t be addressed via code…without a deprecable workaround!!!?!?! unbelievable!! they should read pragmatic programming at adobe!

in the future I will use AS3 only when I need to use papervision!
rants off 🙂
I’ll try the Event.RENDER solution

for me the problem was that inside the mc there was a label who wasn’t accesible only the SECOND TIME that the timeline went back to frame 1.
so mc.myTextField was yielding the infamous ERROR 1009
Cannot access a property or method of a null object reference
(again, only on the second round)

To solve the issue
– I ensured that the textfield had no blank frames..and that was “alive” for the whole timeline..
If you have to make it disappear, bring it to alpha 0 and leave the frame alive untill the end of the mc
– ensure that at every keyframe your child object (in this case the textField) has the same identical instance name
(for a distraction I had one of the keyframes with a different instance name without noticing.)

I dind’t have to use the Event.RENDER-ivalidate ignoble workaround!
nor the addFrameAction
nor I will try to need it in the future (screw AS3)
😉

In Adobe Director, you can force the stage to render using updateStage() command. Very useful.

Event.RENDER is passive and not as easy.

If you’re not uptight about scripting on the timeline, it’s even easier to call a function in the document class from the frame in question, this will be called after the frame is drawn so all mc’s will be “seen”.

I found a related bug that has the same symptoms as above – in the case where using the render event and addFrameScript don’t work.

It has to do with setChildIndex and I am pretty sure it is an adobe bug.

Here is an example to illustrate:
1. Pretend in frame 5, your movieclip has 5 children.
2. gotoAndStop(10) where there are 10 children. Set its index to 5.
3. return to frame 5. the movieclip that was at index 5 loses its reference, although it still appears.