Using Swiz Part 3: Events
Jan 23
In the last installment, we saw how Swiz can help you by resolving dependencies between your ActionScript classes and MXML components. But I left you with a very simple example, hardly more than a "Hello World". In this entry, I'd like to start digging into a more "real world" use of Swiz.
Based on some comments I've gotten on and off the blog, I'm uploading an interim version of the application with view source enabled. You can see it at http://www.briankotek.com/examples/swizdemo_events/Main.html. Keep in mind that in order to get it to a runnable state, the code contains a good number of things that I haven't talked about yet. Look around if you like, but for now don't pay too much attention to something if you aren't sure what it's doing yet. I'll get to it all, I promise! :-)
(A small note, right now there is an issue with the "fake" server calls that can cause the busy cursor to remain on screen. I believe this is a small issue with the test utility included in the Swiz library, and I'm going to mention it to Chris. For now, just ignore it heh).
Judging by questions on the Swiz discussion list, many people are a bit unsure of when things happen and when you are cleared to actually work with the beans that Swiz manages for you. If you run a Swiz application in debug mode, you should see some trace statements in the console that note several steps in the process. However, keep in mind that Swiz must create your objects first, and then autowire them. Which means that the dependent classes will not be available when your object is created, and references to dependent objects in your constructor will cause an error since the dependency hasn't been set yet.
The same is true for views, in that view components are not autowired until they are added to the stage, which is occurs near the end of the component lifecycle. It happens after creationComplete, which means you are not safe referencing dependencies in that event handler. Further, because of the fact that Flex events like creationComplete execute in sequence from the innermost child up through the display list hierarchy to the root container (the Stage), you must exercise even more care. (And that is a general issue for Flex development, not really specific to Swiz).
I've found that the easiest way to deal with issues like these is to minimize reliance on creationComplete, as well as minimizing situations where you try to pass data into a visual component from a parent. For example, consider:
<view:UserContainer id="userContainer" width="100%" height="100%" users="{userController.users}" />
It might look OK on the surface, but we can run into issues if the UserContainer component does something like this in it's creationComplete handler:
private function creationCompleteHandler() : void
{
if( users.length > 0 )
{
// do something
}
}
You see the problem? When UserContainer's creationCompleteHandler runs, it's parent hasn't had the controller autowired into it yet! Which means the reference to users in the UserContainer will be null. In fact, the parent hasn't even had the controller autowired into it yet. As an aside, some of the most difficult initial mental obstacles I faced when starting with Flex was this issue of creation timing. It can get pretty nasty when you have several levels of components, each depending on something provided by their parent. But I digress.
Basically I've found it best to let the application set itself up and THEN dispatch an event that begins populating things with data. And this is where I can also introduce the Swiz CentralDispatcher. In my user manager application, I need SOMETHING to set off processing that gets the list of users and displays it in the data grid. I used a simple approach like this in my Main.mxml file:
private function applicationCompleteHandler( event : Event ) : void
{
Swiz.dispatchEvent( new Event( UserController.APPLICATION_LOAD_REQUESTED ) );
}
So once this event fires, that means all of the child components have been created, added to the stage, and had any Swiz beans autowired in. At this point, I know the application is in a state where everything is ready to go.
Right away, you may notice the first advantage of Swiz's event dispatching mechanism: it doesn't require custom or framework-specific Events. Frameworks like Cairngorm demand that you use their "special" Event objects. Not so with Flex. You can use custom Event types if you like, or you can use standard Flex events. It's one less framework dependency.
Note that Swiz makes using it's event dispatching mechanism as simple as possible by providing static methods on the Swiz class to handle listening for and dispatching events. It's just one more nice convenience that Chris had the foresight to add.
The benefit of using a central dispatcher like the one Swiz provides is to get around an issue with the way Flex normally dispatches events: they only "bubble UP" the component hierarchy. There's no easy way to get CHILD components to respond to an event that is dispatched by a parent. By dispatching events through the central dispatcher, any class can listen for events of interest, regardless of where they sit in the hierarchy.
If you look at the controller code that handles this APPLICATION_LOAD_REQUESTED event, it's a standard event listener and corresponding handler. The only difference of note is that the listener is configured on the Swiz central dispatcher:
public function UserController()
{
super();
users = new UserListCollection();
Swiz.addEventListener( APPLICATION_LOAD_REQUESTED, loadUsers );
}
public function loadUsers( event : Event ) : void
{
executeServiceCall( delegate.loadUsers(), userLoadHandler );
}
Ignore the "executeServiceCall()" method for now, we'll get to that in the next entry. The point is: from here, my application kicks off the process of getting the user list and then providing it to the view. If you look at the attached code, you can see that the Swiz central dispatcher is also used to move data into the view.
That's all for now. In the next entry, I'll look at how Swiz makes getting data from the server just as easy.
Comments (9) |
del.icio.us
|
Digg It!
|
Linking Blogs
| 7364 Views


# Posted By Russell Brown | 1/23/09 3:33 PM
Alternativly:
private function applicationCompleteHandler( event : Event ) : void {
Swiz.dispatch(UserController.APPLICATION_LOAD_REQUESTED);
}
-------------------------------------------
public function UserController() {
super();
users = new UserListCollection();
}
[Mediate(event=UserController.APPLICATION_LOAD_REQUESTED, properties="user")]
public function loadUsers() : void {
executeServiceCall( delegate.loadUsers(), userLoadHandler );
}
# Posted By Russell Brown | 1/23/09 3:35 PM
Also for something with needed passed values seeing as how I left part of my properties text in my mediate meta data by mistake on my copy and paste. My above Mediate code should not have a properties argument.:
private function applicationCompleteHandler( event : Event ) : void {
Swiz.dispatchEvent(new LoadRequestEvent(myParameterValue));
}
-------------------------------------------
public function UserController() {
super();
users = new UserListCollection();
}
[Mediate(event=UserController.APPLICATION_LOAD_REQUESTED, properties="myParameterValue")]
public function loadUsers(myParameterValue:String) : void {
executeServiceCall( delegate.loadUsers(), userLoadHandler );
}
# Posted By Brian Kotek | 1/23/09 3:36 PM
Thanks Russell, but one thing at a time please! I deliberately didn't include mediated event handlers because I'll be covering that (among other things) in upcoming entries. :-)
# Posted By Brian Kotek | 1/23/09 3:40 PM
To readers less familiar with Swiz, I should add: don't get confused by Russells comments please. If you want to investigate event mediators right away, feel free, but if not, don't worry, this will all be discussed. Just trying to move along in small, focused steps. Thanks!
# Posted By Chris Scott | 1/23/09 10:19 PM
Not to be confusing but... I do something very similar to what Russell posted to get my controllers to build initial data.
-C
# Posted By Sönke Rohde | 1/24/09 10:20 PM
Brian, the bug with the busy cursor was my bad I think.
If I remember right the delay has be at least 100ms or a bit more and things should work correctly. What delay did you use?
# Posted By Nathan Mische | 1/26/09 5:13 PM
@Russell: I see you are using a constant for the event type in you Mediate annotation. Does that actually work? I thought you had to use a literal value? Thanks.
# Posted By Sönke Rohde | 2/3/09 2:20 PM
@Nathan: It works when you set Swiz.setStrict(true)
The value should be the full qualified classname and the event constant at the end. Example:
[Mediate(event="com.foo.event.MyEvent.CHANGE")]
The value of MyEvent.CHANGE is resolved at runtime.
# Posted By Vinoth | 5/10/10 11:11 AM
Is there any special way to call a webservice method name or the same procedure. My WebService method name is not being called.