One of question on Flex Interview could be: "How would you pass some
extra data into the item renderer instance? Or how item renderer can
access application level data?". Here is some obvious renderer for
displaying logged user and his pet in specified color.
<customrenderer> <mx:Script> <![CDATA[ [Bindable] private var settingsModel : SettingModel; [Bindable] private var userModel : UserModel; ]]> </mx:Script> <mx:Label text="{usermodel.loggeduser + " " + data.petname}" color="{settingsModel.selectedColor}"/> </customrenderer>
Few of possible answers on initial flex question could be:
1. Using outerDocument to get access parent document. But this step
mess components dependency and can prevent item renderer reuse.
2. Declare application level models as singletons. In theory it is bad
architecture that use a lot of singletons but I think it’s “okay” way
for small and medium projects. So in example we will have:
[Bindable] private var settingModel : SettingsModel = SettingsModel.instance;
3. Solution you can find on adobe site is using flex
ClassFactory and passing factory. Look at Setting
the properties of an itemRenderer from MXML
Now let me introduce dependency
injection that could be another helpful solution for item
renderers. This pattern helps us to pass userModel and
settingsModel in more elegant way (but not easy in technical
side :-) ). According definition of dependency injection it consists
of 3 elements:
* component which has dependency to another object - CustomForm;
* object that should be setted - instances of settingsModel and
userModel;
* provider that will do dirty that job for us. It will set objects
into component. It should be fully featured so first two have less
changes as possible.
Now let's use power of actionscript events and reflection to solve this problem. I'm going to use FlexEvent.ADD which dispatched when item renderer added to list. Each child in flex form dispatches this event and I can inject dependency in that which implements some marker interface IModelAware.
// subscribe for <i>FlexEvent.ADD</i> from main view addEventListener(FlexEvent.ADD, onChildAdded, true); ... private function onChildAdded(event : Event) : void { var comp : Object = event.target; if (comp is IModelAware) { // view requires links to models DependencyUtil.injectModels(comp); // last method use reflaction for taking all // public props from one object and tries // to set them to another one // that could be achieved via <i>describeType</i> flex util } }
Metadatas can be
used as interface but it is a little harder to access.
Other open question for me is how to inject dependency into components defined in mxml. Event.ADD is not dispatched for that case.