Using RobotLegs to Create a Widget for the ArcGIS Viewer for Flex

Thu, Mar 17, 2011 4-minute read

I submitted two talks to last week’s ESRI Developers Summit, one of which was not selected.  This made me indignant enough to write a blog post explaining the shunned presentation, in the hopes that all the people that did not vote for it will slap their foreheads and pray for the invention of time travel.  Or, maybe I just want to dialog on using Robotlegs with the Flex Viewer.

In the Advanced Flex presentation that Bjorn and Mansour gave at DevSummit, he extolled the use of frameworks.  Paraphrasing, he said “Find a framework and stick with it”  By “framework”, he meant something like PureMVC, Cairngorm (3, mind you, not 2), or Robotlegs.  I agree with the sentiment, wholly, although I am also a bit baffled at why the Flex Viewer didn’t use one.  My guess is that they will claim they have their own framework, which is certainly true, but it flies in the face of what Mansour spoke of in his presentation.  I raised my hand to ask this question, but (thankfully) time ran out on the questions and I was not selected.  It is probably just as well, as I don’t want to get on Mansour’s or Bjorn’s bad side.  They’ve both been very helpful to me in the past and I doubt I am even close to beyond needing more of their knowledge.

So, in this blog post, I am going to create a Flex Viewer Widget with Robotlegs.  First, though, I’ll explain a couple of things.  The reason I like using Robotlegs (or any well-supported framework) is myriad. It makes my widget much more testable, meaning, I can more easily write unit tests to exercise the widget.  This allows me to design the widget in a test-driven fashion, which is a good thing.  I wonder why the Flex Viewer source doesn’t include any unit tests.  Again, it’s not like ESRI is promoting bad habits, but they aren’t promoting good ones either.  Also, Robotlegs is known outside the ArcGIS world, so future Flex developers on my project that know Robotlegs will be able to get productive more quickly.  Granted, they’ll still have to learn about the ArcGIS API for Flex as well as the widget-based approach taken by the Flex Viewer, but the patterns Robotlegs uses brings context to this learning.  That’s my story, and I am sticking to it.

So, why Robotlegs?  Because I like it.  It’s got a great community and it makes a ton of sense.  Read on to see what I mean.

OK, let’s get to the code.

Now, I don’t really want this post to be an intro to Robotlegs.  There are plenty of those, including a very recent one by Joel Hooks (an RL founding member and crazy-smart guy) Read through those posts (as of this post, there are 3, with more on the way)  It should get you enough background to understand what is going on here.  Go ahead, I’ll wait.

Back? Confused? Robotlegs takes a bit to comprehend (not even sure if I totally get it, ahem) So, here are the things you’ll need to go through this in your own Flex development environment:

For simplicity, just grab the git repository here, which has all this stuff set up for you.  Don’t get too hung up on the number of libraries and third party code.  This is how separation of concerns looks, leveraging the best library for a specific function.

In the main application context, we register the BaseWidget class, which will allow Robotlegs to inject any widget going forward.  This makes using Robotlegs a bit more involved than just sticking with the “core” Flex Viewer widget approach, but it’s a small price to pay, in my opinion.

public function get x():Number{ return _x; } public function get y():Number{ return _y; } public function Geolocation(x:Number=0.00,y:Number=0.00) { _x = x; _y = y; } }

public function GeolocationEvent(type:String) { super(type); } override public function clone():Event{ return new GeolocationEvent(type); } }

[Inject] public var event:GeolocationEvent;

override public function execute():void{ service.getGeolocation(); } }

public function handleLocationNotFound():void{ var event:GeolocationEvent = new GeolocationEvent(GeolocationEvent.LOCATION_NOT_FOUND); dispatch(event); } }

widget.currentState = GeolocationWidget.STATE_SEARCHING_FOR_LOCATION; getLocation(); }

public function handleLocationNotFound(event:GeolocationEvent):void{ widget.currentState = GeolocationWidget.STATE_LOCATION_NOT_FOUND; }

override public function startup():void{ //Singletons injector.mapSingletonOf(IGeolocationService, GeolocationService); injector.mapSingletonOf(IGeolocation,Geolocation);

//Mediators
mediatorMap.mapView(GeolocationWidget, GeolocationWidgetMediator);

//Commands
commandMap.mapEvent(GeolocationEvent.GET_LOCATION, GetGeolocationCommand,GeolocationEvent);
commandMap.mapEvent(GeolocationEvent.LOCATION_FOUND, FindPolygonCommand, GeolocationEvent);

} }