Thursday 21 January 2010

Asynchronous Commands in Parsley 2.2

I’ve been working with the latest version of parsley at work over the last few days and it’s got a really nice new feature borrowed from Cairngorm 3.0. It makes it much easier to deal with asynchronous operations. Previously if I was going to load something I might need all these files:

  • model that wants the data
  • loadData event – possibly with payload
  • Action to receive load event
  • service
  • ResultEvent
  • FaultEvent

Now we can get rid of a lot of these classes and end up with:

  • model that wants the data
  • loadDataEvent
  • service

You don’t actually need a custom event for the load either as you can just use a normal event and use string based matching but I prefer to match on class rather than string.

Let me give an example. In my Picasa API demo I had the following code in my LoadPicasaAlbumList action:

[MessageHandler]
public function loadAlbumList( event : ListPicasaAlbumsEvent ) : void
{
var token : AsyncToken = service.loadUserEntries( event.userID, PicasaService.KIND_ALBUM );
token.addResponder( this );
}
public function result( data : Object ) : void
{
var resultEvent : ResultEvent = ResultEvent( data );

var collection : ArrayCollection = PicasaTranslator.desearialiseXML( XML( resultEvent.result ) );

dispatchEvent( new ResultEvent( LIST_ALBUM_RESULT, false, true, collection, resultEvent.token, resultEvent.message ) );
}

public function fault( info : Object ) : void
{
var faultEvent : FaultEvent = FaultEvent( info );

dispatchEvent( new FaultEvent( LIST_ALBUM_FAULT, false, true, faultEvent.fault, faultEvent.token, faultEvent.message ) );
}

Along with a load of meta data tags at the top of the class. This class is no longer required – which is good as it’s a load of boring boilerplate code that doesn’t really do very much and is tedious to write.

Now we have the following:

Model:

protected function loadFeed() : void
{
albums = null;
dispatchEvent( new ListPicasaAlbumsEvent( userID.text ) );
}

Service:

[Command( type="com.pricklythistle.picasa.event.ListPicasaAlbumsEvent", messageProperties="userID,kind" )]
public function loadUserEntries( userID : String, kind : String = null ) : AsyncToken
{
if( !kind )kind = KIND_ALBUM;

if( ArrayUtil.getItemIndex( kind, KIND_ARRAY ) < 0 )
{
throw new Error( "kind must be found in KIND_ARRAY" );
}

url = StringUtil.substitute( BASE_URL, userID );

return new AsyncTokenWrapper( send( { kind : kind } ), PicasaTranslator.desearialiseXML );
}

Which is exactly the same code I had in the service originally except for the Command metadata tag. It instructs parsley to fire that function when an event of the correct type is received and tells parsley what properties to pass into the function.

Model:

[CommandResult]
public function onAlbums( albums : ArrayCollection, event : ListPicasaAlbumsEvent ) : void
{
this.albums = albums;
}

[CommandError]
public function onAlbumsFault( fault : FaultEvent, event : ListPicasaAlbumsEvent ) : void
{
trace( "fault" );
}
}

Parsley calls these functions when the command completes or fails and passes either a ResultEvent or your data in according to how you type the arguments.

And the really clever bit:

[Bindable]
[CommandStatus( type="com.pricklythistle.picasa.event.ListPicasaAlbumsEvent" )]
public var loadingAlbum : Boolean;

This populates the property with a Boolean value of true when the data is loading so that you can disable buttons / show a loader or do whatever you want.

For more details about the Command tags take a look here.

2 comments:

  1. Hi gilles!

    At first glance, I don't see any difference with cairngorm 3. Is there any?

    Xavier

    ReplyDelete
  2. I've not actually looked at Cairngorm 3 but I doubt there are any differences. Jens himself says in this forum post:

    http://www.spicefactory.org/forum/viewtopic.php?p=1778&sid=eb64566d0dce012f1ea42630189ca102#1778

    that it is based on Cairngorm 3 and gives credit to them.

    ReplyDelete