Communicating Between Components In Flex

For a monday post, I'll review a what not to do and an idea of how to do it better.

As I first began my foray into the wonderful world of Flex, I entered without any real conception of OOP; I have, like many others, been discovering the joys and pains of that as I moved along. One of the wonderful things about not knowing what I was doing was experimenting with some really stupid ideas. Sarcasm aside, I really am glad for the experience of trudging about blindly as I am started to come to conclusions that I am finding out are pretty well aligned with best practices, though I have a lot of traveling left in this journey.

One of the more stupid things I have done, was to wonder why objects did not have a builtin reference to the object that called them. From my HTML & Javascript past, I lamented the loss of a reference to an "opener"-like handle and, being the clever sort, I implemented it.

My thought was that if I create a custom component and place it somewhere in my Application, it ought to directly invoke functions in its parent container. Even better, I could navigate up the change through successive use of my custom properties. I really don't want to dwell on this, as it is not a good way to do anything, however, for historical reference, here's what I did:


<mx:Script>
<![CDATA[

// Generic reference creator reference

private var _creator:Object;

public function set creator(obj:Object):void {
_creator = obj;
}

public function get creator():Object {
return _creator;
}

public function dontDoThis():void {
_creator.someFunction();
_creator.someProperty = this.someOtherProperty;
}

]]>

</mx:Script>

and in calling the code, it would be something like this:


<mx:Script>
<![CDATA[

private var _myObj:Object;
private function somePseudoProtoFactory():void {
    _myObj = myCrappyComponent();
    _myObj.creator = this;
    
    // now do something with this
}

public function someFunction():void {
// do something
}

public var someProperty:Object;

// Note: I kept everything as Objects to keep it completely generic for the example

]]>

</mx:Script>

Now, this will work. The component has access to the public members of its parents and you have a whole lot of rope to hang yourself. Encapsulation is a foreign concept here, and from personal experience, you meet the gallows as soon as you either A) want to change something or B) want to reuse the component.

You don't want to be staring at the following a few months later:


<mx:Script>
<![CDATA[

// bad bad bad
creator.creator.creator.doSomething();

]]>

</mx:Script>

This sucks because you now have to go spelunking through multiple components so you can divine your original intent. Your functionality is spread of multiple elements and you have dependency issues galore. As the comment says: bad bad bad.

Instead, you want to do what is painfully obvious to others and similar to the following:



<mx:Metadata>
[Event(name="MyEvent", type="flash.events.Event")]
</mx:Metadata>

<mx:Script>
<![CDATA[

public const MY_EVENT:String = "MyEvent";

private function handleMyEvent():void {
    dispatchEvent(new Event(MY_EVENT));
}

private function doingSomething():void {
    // do something
    handleMyEvent();
}

// The actual form of this will probably change in a
// particular implementation, but this should convey
// the idea

]]>

</mx:Script>

Now instead of some crazy chain of parent references, the component is ignorant of anything other than its own local concern. If required, the chain reaction can be accomplished using the following:



<mx:Metadata>
[Event(name="MyParentEvent", type="flash.events.Event")]
</mx:Metadata>

<mx:Script>
<![CDATA[

public const MY_PARENT_EVENT:String = "MyEvent";

private function doInit():void {
myChildComponent.addEventListener(myChildComponent.MY_EVENT,doListenToChildEvent);
}

private function doListenToChildEvent(e:Event):void {
// optionally, do something locally
handleMyParentEvent();
}

private function handleMyParentEvent():void {
    dispatchEvent(new Event(MY_PARENT_EVENT));
}


// In practice, pay a lot more attention to managing your event listeners
// the above is quick and dirty

]]>

</mx:Script>

As you can see, the parent is listening for the event and is dispatching its own event. The idea is that no level need assume the responsibility for knowing anything in the outer world.

This is somewhat basic, but since I screwed this up for awhile, hopefully I can help somebody else avoid this mistake.

Related Blog Entries

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
BlogCFC was created by Raymond Camden. This blog is running version 5.9.1.001. Contact Blog Owner