flex, component's life-cycle


Earlier today I fixed a minor code issue. It took seconds to identify, but I remember being a little stumped by a similar problem in my early Flex days. The difference now is that I'm familiar with the component life-cycle.

You may think it is only worth reading up on the Flex component life-cycle if you intend to create advanced components, but that's not true, even when you are doing nothing other than extending basic mxml components a little knowledge goes a long way.

To demonstrate the problem take a look at the init method for this simple mxml component called TimeInputBar (which extends Canvas).


      //<code>Init</code> is called when the component's <code>initialize</code> event is fired:
      public var time:Number;
      public function init():void
          time = 0;

That's simple enough. Now take a look at the ActionScript which is creating an instance of the TimeInputBar:


      var t:TimeInputBar = new TimeInputBar();
      t.time = 12;

Again, simple code, but did you spot the problem? With a little bit of knowledge it's easy to see that time will always be reset to 0 and will never be 12. Why?

When you create a component using the new operator, only part of the life-cycle completes. The component gets as far as the configuration stage, which means you can set properties on the component (to be processed by the component later) but the life-cycle will not go any further than that. It is in effect, paused.

However, all the really cool stuff in the life-cycle, like creating the component's child elements, measuring the component, drawing the component and dispatching events happens during the next stage.

It is only when you add the component to the display list using addChild or addChildAt that the life-cycle continues (in other words ... it continues when the component has a parent).

As mentioned, the next phase is the one in which the cool stuff happens: In more detail, this means that the preinitialize event is dispatched, the component's children are created, the initialize event is dispatched and the component's validation methods are called (those are beyond the scope of this article) and if that's not enough for you, when all that is done then everybody's favourite event, creationComplete is dispatched.

So, with that knowledge in hand let's revisit the order of execution for the original example:

  • Create component using 'new' operator
  • Set time variable to 12
  • Add component to display list
  • initialize event is fired
  • init() method is called
  • time variable is set to 0

Many beginners make the assumption that the preinitialize and initialize events are dispatched early on - don't beat yourself up, that's a reasonable assumption to make. However those events may actually be dispatched after you've set initial values for some of your component's properties.

So, what's the solution? We could simply swap the order of our code:


      //no worky!
      t.time = 12;
      t.time = 12;

...but I'm hoping you can see the issue; components should be just a little more flexible than that!

A perfectly acceptable solution here would be to perform a simple check inside our init method:


      public var time:Number;
      private function init():void
          if(isNaN(time)) time = 0;

[Edit - it's also perfectly acceptable to set 'time' to 0 when you first declare it - this post is not really concerned with which solution you choose, but rather it uses simplified code to explain why such a problem may arise in the first place.]

Once that is done, it will not matter if you set time before or after you add your component to the display list. If the value is set externally before init is called, the value will not be overridden.

You can read a little more about the Flex component life-cycle in one of my earlier posts here.