Lazy Model Responder

Within a Flex application it is a very common thing to show lists of items or domain objects for instance a list of articles, users or whatever.
There are many ways to implement this and I would like to share an approach which I call Lazy Model Responder. I am using the Cairngorm microarchitecture where I implement the ModelLocator, BusinessDelegate and ServiceLocator.
The ModelLocator provides a reference to my Lazy Model Responder instance which uses the BusinessDelegate which relies on the ServiceLocator.

package mypackage
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
 
	import mx.collections.IList;
	import mx.logging.ILogger;
	import mx.logging.Log;
	import mx.rpc.IResponder;
	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;
 
	public class LazyModelResponder extends EventDispatcher implements IResponder
	{
 
		private static const logger:ILogger = Log.getLogger("LazyModelResponder");
		private static const ITEMS_LOADED:String = "itemsLoaded";
 
		private var _items:IList;
		private var _pending:Boolean = false;
 
		[Bindable(event=ITEMS_LOADED)]
		public function get items():IList
		{
			if(_items == null)
			{
				loadItems();
			}
			return _items;
		}
 
		private function loadItems():void
		{
			if(!_pending)
			{
				logger.info("load items");
				pending = true;
				// MyDelegate expectes an IResponder in the
				// constructor to add it to the AsyncToken
				new MyDelegate(this).loadItems();
			}
		}
 
		public function result(data:Object):void
		{
			_pending = false;
			var re:ResultEvent = data as ResultEvent;
			_items = IList(re.result);
			logger.debug("items loaded. count: ", _items.length)
			dispatchEvent(new Event(ITEMS_LOADED));
		}
 
		public function fault(info:Object):void
		{
			_pending = false;
			var fe:FaultEvent = info as FaultEvent;
			logger.error("loading failed ", fe.message);
		}
 
	}
}

The class implements the IResponder interface (methods result and fault) and a getter where a view can bind against:

[Bindable(event="itemsLoaded"]
public function get items():IList;

The Data Binding within the view is always updating when the itemsLoaded event is fired within the class.

The view could look like this

<mx:List dataProvider="{MyModelLocator.getInstance().myModelResponder.items}" />

When the view comes into the display chain the data binding is invoked which calls the items getter. There is no setter as this is read-only.
This calls loadItems which loads the data over the delegate and sets pending to true to be called only once. “Null” is returned when items getter is called the first time which is fine for the view as it shows nothing but triggered the backend call with its existence / data binding.
Depending on the success of the call the fault or result method is called which sets pending back to false. If the call was successfully the data is stored in the result method and the itemsLoaded event is fire. This triggers the refresh of the data binding. The items getter is called again but this time the _items are not null so the list is returned which lets the data show up in the list view.
The view can of course also be a DataGrid or any other view which can render a list or in this case implements the IList interface.

Another possibility would be to not use the ModelLocator but setting the data binding outside of the view which would simplify unit testing for instance.

2 comments to Lazy Model Responder