Reusing Views with different Mediators
Hi, all;
I have a current system in place where I create a new stub view to use whenever the data being mediated is slightly different, as recommended by Joel Hooks (http://knowledge.robotlegs.org/discussions/problems/6-mxml-componen...). However, this has become a politically difficult solution, because as the system grows we will wind up with at least 250 Views.
My colleagues are Chinese, and no matter how many times I say "there is 0 effort to creating these views," this is not getting through to them. I'm not sure if this is a language barrier, or if it's just the natural distates just about any programmer would have for having to maintain a Class that's only necessary because of the Framework we're using.
So my job is to find a solution that politically satisfies them, before they rewrite this to something I fear will not be at all maintainable. Each View is created by a factory and placed into a renderer. Currently, the renderer doesn't know much about the data (but might know enough to set up a child injector) and the View knows nothing about the data, except what is fed it from the Mediator.
Would child injectors be a good solution here? If so, where can I find a good example?
Also, is there any mileage to the idea that the renderer could simply create the Mediator directly, since it is already handling addChild() on the actual View? If there is only one Mediator that's relevant to that child injector, how much is it really doing for me?
TIA;
Amy
Comments are currently closed for this discussion. You can start a new one.
Keyboard shortcuts
Generic
? | Show this help |
---|---|
ESC | Blurs the current field |
Comment Form
r | Focus the comment reply box |
---|---|
^ + ↩ | Submit the comment |
You can use Command ⌘
instead of Control ^
on Mac
1 Posted by Amy on 19 Oct, 2010 02:49 PM
I've been plowing on with this, trying to use child Injectors. But what I'm finding is that the parent injector is not getting injected into the child View
Here's the code in the Child:
[Inject] public function set parentInjector(value:IInjector):void {
}
This code does not run, even though the mediator that is mapped to the child attaches just fine (implying that the parent context is set up properly). I also did a trace in the parent context to see that the injector has a mapping for IInjector, and it does.
What to try next?
Thanks;
Amy
2 Posted by Stray on 19 Oct, 2010 02:58 PM
Hi Amy,
I did have a ponder on this, but I've drawn a blank so far.
Either they're the same (in which case a single mapping will work), or they're different... in which case they deserve subclassing.
The bigger your system the more important it is that you adopt good practices, and in my opinion stubclasses for things that are different are good practice, whether there's 2 of them or 200 of them. I know you're sold on this yourself... but I guess you're swimming against the tide here.
You could, however, definitely create your mediators manually - if they don't declare a view as a dependency you can instantiate them with the injector and then give the view and run onRegister manually just as you would in a TestCase for that mediator.
Whether there's a more elegant solution... not sure... !
Hopefully others will have thoughts too...
Cheers,
Stray
3 Posted by amy on 19 Oct, 2010 03:13 PM
The second issue...I realized that I'd forgotten I had to map a view for it to receive injection. Hopefully, now I am past that I will figure out the rest soon.
The first issue is kind of complex. Where we have simple views that are just one line of data and another line for the units, I totally see where they are coming from. It seems silly to have to have a separate View Class to do that, when the difference is only in the data.
As the system grows to include guages, histograms, etc., I suspect that having one view per different type of data will be more than useful (our industrial design department changes requirements frequently). However, to get everyone on board I need to prove it can at least be done, even if we choose not to do it in the end.
As they say in Scotland, a real gentleman is a man who can play the bagpies...but doesn't. I have to prove I can play the bagpipes before I can even have the discussion about whether we should.
Thanks!
Amy
Support Staff 4 Posted by Shaun Smith on 19 Oct, 2010 03:19 PM
Hi Amy,
I'm afraid I'm struggling to see what you are wanting to achieve. If your renderers are coming from a factory, why not wire them to mediators manually in the factory when you create them?
Is there a particular reason for wanting child injectors and separate contexts for each renderer?
5 Posted by Amy on 19 Oct, 2010 03:35 PM
For one thing, we have an existing system where that factory is used and I don't want to disrupt what it does. I also don't want the factory to know or care about RobotLegs. It has one job, which is to look at the incoming data and parse it into a state, which happens to include a particular Class the Renderer adds to itself. And how would it connect the Mediator to the Context, which is what has the mappings?
If anything, the renderer should wire up the mediator, but I wasn't sure if that would "violate" some principle of RobotLegs. That's why I asked the question.
This system is an extension to an existing system, so I'm also concerned that if I add a Mediator manually, what happens to Views that are already covered in the existing system if someone accidentally adds a conflicting Mediator on top of them? Could I wind up with two Mediators fighting to change the data in the View?
Is there a mechanism by which I could remove a Mediator if it were in conflict with the one I wanted to add manually (that would be accessible in a child View of the one containing the Context or could be accessible to a Command)?
It seems to me that child injectors were invented to handle something like this, but there is frustratingly little information on how to use them.
Thanks;
Amy
6 Posted by amy on 19 Oct, 2010 04:08 PM
OK, so I got that working, but I'm winding up with another conundrum... I am mapping the renderer in its own child context, with the intention that when I map a Command there, the Command will execute on the mediatorMap belonging to the local context and perform the remapping.
The code looks like so:
public class DataViewRendererContext extends Context
{
}
The problem with this is that the eventDispatcher used in the child Mediator is actually the one used in the parent context, not the child context. Is this a bug?
If not, the only alternative I see is mapping the command in the parent context and exposing the protected mediatorMap for the child context so it can be passed in the Event. Is it just me, or does that feel icky?
Thanks;
Amy
Support Staff 7 Posted by Shaun Smith on 19 Oct, 2010 04:14 PM
Hi Amy,
Fair enough, that rules out the factory injector approach then.
The simplest explanation of child injectors comes from the IInjector.createChild() asdoc: "Create an injector that inherits rules from its parent."
More info on how this is handled by SwiftSuspenders can be found under "Child Injectors" in the README over at: http://github.com/tschneidereit/SwiftSuspenders
"child injectors forward all injection requests they don’t have a mapping for to their parent injector."
It's kinda like CSS.
I wouldn't worry about "violating" principles - the RL best practices are just recommendations, something to get started with. Every app is different.
(I see another post has come though, so will stop here)
Support Staff 8 Posted by Shaun Smith on 19 Oct, 2010 04:19 PM
That doesn't sound right, no. Could you try moving your mappings into the startup() hook?
9 Posted by Amy on 19 Oct, 2010 04:55 PM
Yay! That worked!
I have a(n almost) working proof of concept now, and it has certainly taught me why a stub view is more portable. In order to use this mediator, I now need to carry around the infrastructure to look at the factory and remap the mediatorMap. What a pain!
Now, if I knew how to say this in Chinese... ;)
Stray closed this discussion on 10 Feb, 2011 06:03 PM.