Injected Singleton Is Not Available in View
Trying to upgrade from RL v1.0.3 to v1.1.2
In the former version, I was able to create a property to a mapped singleton with the [Inject] metadata tag and it would be not null
In the latter version, the view component is set to null as if it wasn't injected.
it's been a couple of months since I was last here. Can anyone point me in the right direction? Perhaps release notes?
Thx
-mL
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 Mark Lapasa on 26 Aug, 2010 03:55 AM
Correction: In the latter version, the view component's property to that mapped singleton is set to null as if it the singleton instance was never injected into the view.
2 Posted by Jason Dias on 26 Aug, 2010 07:32 AM
Hey Mark,
Being able to Inject into views that were mediated without having to add the view to the injector was actually a bug with RL, and has been fixed.
You should pass the singleton into the view through it's mediator, or if you really need to inject into the view you can map the view to the inject like so:
I hope this helps you.
Jason
3 Posted by Mark Lapasa on 26 Aug, 2010 12:31 PM
Jason, thx man. That did it. Quite a few changes to our code but it works. Most appreciated.
4 Posted by AMo on 02 Oct, 2010 10:16 AM
So, what's the recommended way to inject into views?
It seems to violate DRY if I have to first inject a model into a mediator and then set that model on the view. It's 7 lines of code instead of 3 (including the metadata and imports). 3 of those lines are repeated.
Why is it a bug to auto-wire views that are already known to the injector (indirectly via the mediator)?
Injecting the injector itself into the mediator just so you can then use the injector to inject dependencies into the view also has a bad code smell.
I'd like to hear reasons/rationale/logic for why auto-injecting dependencies on views by default, is a bad idea/bug.
I'd also like to hear from anyone who has a more elegant solution to this problem.
I haven't tried yet but the best idea I've come up with so far is this:
1) subclass Mediator => ViewInjectingMediator
2) in ViewInjectingMediator, inject the injector:
3) in ViewInjectingMediator override
onRegister()
thus:viewComponent is inherited from MediatorBase.as and is a reference to the mediator's view component presumably set by the framework somewhere - I haven't checked.
4) create a new abstract method:
5) In my project, instead of subclassing Mediator, I subclass InjectingViewMediator for all of my mediators where I want the view to be automatically injected.
6) When using that subclass, instead of overriding
onRegister()
(I could make it final), you have to instead overrideonInjectedViewRegister()
Apart from the dubious class and method naming, does anyone have any better ideas or see problems with this approach?
Ideally, this would already be part of the framework in MediatorBase.as. I guess the view could be injected somewhere in
preRegister()
. What am I missing?5 Posted by AMo on 02 Oct, 2010 10:48 AM
I see this was previously discussed [here] (http://knowledge.robotlegs.org/discussions/problems/149-injection-i...) but a full explanation was not given.
I couldn't see any mention of not being able to inject into views in the documentation. If you're coming from another framework like Swiz, this could have you stumped.
Look forward to further responses.
Support Staff 6 Posted by Shaun Smith on 02 Oct, 2010 11:54 AM
Hi AMo,
Injecting application actors directly into view components defeats the purpose of the mediator pattern. If you prefer the presentation pattern you should stop using the MediatorMap and use the ViewMap instead:
The ViewMap injects directly into view components as they land on the stage (inside the contextView).
I wouldn't recommend using the MediatorMap and the ViewMap in the same application - using two opposing patterns to manage your view will inevitably result in a confusing mess (and there is a performance penalty to pay).
OK, with all that out of the way, if you really do want to inject into mediated view components, you can do so by extending the MediatorMap, and overriding "registerMediator" like so:
Then you'd need to provide your specialized MediatorMap to your context (override the mediatorMap getter).
Hope that helps!
7 Posted by Abel de Beer on 02 Oct, 2010 12:00 PM
@AMo: Something important to understand is that the Mediator pattern (in the RL implementation) is a way of seperating your views from the rest of the framework. This means that trying to inject a framework actor (e.g. model, service, etc.) into a view component is overriding this principle! Your Mediator should have a reference to the framework actor and pass its necessary data to the view component, for example through parameter (method/setter) injection. This way the view component will have a clear single responsibility (displaying the data and allow for user interaction) and will not be dependent on a framework actor, thus increasing reusability / portability.
Read more about injection in the best practices documentation:
http://github.com/robotlegs/robotlegs-framework/wiki/Best-Practices...
Also, since Robotlegs is based on the MVC pattern and its implementation has a lot of similarities to PureMVC's implementation, you can check out the following links as well:
http://en.wikipedia.org/wiki/Model_view_controller
http://puremvc.org/component/option,com_wrapper/Itemid,174/
Plus, I'm an Interaction Design student and I wrote a paper a while back about applying the MVC pattern and I use the example of an online game for a museum:
http://abeldebeer.nl/documents/AbeldeBeer_MVC_29-06-2010.pdf
8 Posted by Amo on 02 Oct, 2010 12:27 PM
@Shaun
Thank you for clearing that up for me.
Your suggestion of extending MediatorMap sounds like a good fit for my style of programming (DRY, KISS, maintainable)
I don't see why it would be a confusing mess to use mediators exclusively for mediating application events whilst still being able to directly inject bindable models into the view so that views can easily present the state of the model.
9 Posted by AMo on 02 Oct, 2010 01:15 PM
@abeldebeer
Thanks for your links. I'm already familiar with MVC thanks lol. I read the best practices document before coming on here and I have to say I have to question some of those best practices. One example being that of accessing a service directly from a mediator. That's another discussion though.
Perhaps it's because I'm very familiar with dependency injection from other frameworks (and other languages) that RL seemed at first a bit counter-intutive on this issue. If I'm pulling an object out of an IoC container, I expect it to have all of it's dependencies already injected. Granted, views are not explicitly defined in the container when using mediatorMap.
Shaun has explained the rationale why views are not automatically injected - it seems to be a way to enforce the mediator pattern. But there are different ways to interpret the mediator pattern.
If you have a view that is primarily a form and you want to load the form with the contents of a model and similarly update the model from the view, Flex's (bi-directional) binding is specifically designed for this kind of common use case i.e. to avoid having to write boilerplate event handling code. It's simple, you just:
Now, if you were going to use the Mediator pattern as strictly as you are suggesting you'd have to get rid of [Bindable] altogether and propertyChange events etc. In fact, you imply you wouldn't even have the model on the view at all because that's a "framework actor" and for some reason it's bad for the view to know about it. Your mediator would have to individually set on the view all of the properties from the model at register time (could be one or two or could be hundreds, lets pretend there are 20). Further to acheive the equivalent of the simple bindable model example above you'd have to:
Have you ever tried coding a Flex application like that? Now, imagine your application had 100 forms just like that.
You may get a nice warm feeling inside knowing that you've followed the mediator pattern (as RL has interpreted it) but you will have incredibly poor code that is highly brittle, unmaintainable, violates DRY consiberably and is not developer friendly to write. I ran screaming away from Cairngorm 3 years ago due to these same issues. I'm trying to give RobotLegs a fair go on a real-world project but I'm already missing Swiz.
I apologize if I am laboring the point but form development is a highly common use case when you're developing applications that are largely data driven e.g. back office systems. I'm not talking about toy applications like image galleries etc.
Shaun has suggested using viewMap instead of mediatorMap but I still want to have the views loosely coupled from sending and receiving application events. This is where a mediator would come in. However, it seems it's not recommended to use both viewMap and mediatorMap so I'm stuck with a little hack of extending mediatorMap to achieve what I think is the best of both worlds and a pragmatic solution.
10 Posted by Abel de Beer on 02 Oct, 2010 03:20 PM
@AMo: You've proved your point. I did not mean to offend.
11 Posted by Stray on 03 Oct, 2010 11:05 AM
The Robotlegs MVCS approach is just a set of 'trousers' on the robotlegs. You're free to roll your own version if you prefer.
Binding has its uses, and also its weaknesses - even for back-office form based applications.
There are always going to be use cases that are ideal candidates for the robotlegs textbook approach and use cases that are absolutely not suited to it. Most people, most of the time, are finding that the mediator pattern as RL implements it is a great fit with their needs.
I can't imagine accessing a service directly from a mediator is in our best practices - we advocate always using commands to update models and use services, so that might be a 'but if you really wanted to you could do it this way... ' rather than a best practice.
Support Staff 12 Posted by Shaun Smith on 03 Oct, 2010 04:05 PM
Hey AMo,
Good points, and I agree with many of them.
"If I'm pulling an object out of an IoC container, I expect it to have all of it's dependencies already injected. Granted, views are not explicitly defined in the container when using mediatorMap."
That's exactly it - when using the mediator map the views are not container managed by default, only the mediators are. There are a number of reasons for this:
Performance: Injecting into complex view components can be CPU and memory intensive. Injecting into mediators is cheap and fast. Granted, this is an incredibly minor issue.
Modularity: Sometimes you want to mediate a component that lives in a child module without injecting dependencies as configured by the parent - the module might have its own context with its own rules, and injection from the parent would be undesirable.
Adding behavior is easier than taking it away. Opt-in vs opt-out.
RL's interpretation of the Mediator pattern is that view components should be completely framework unaware. This means no custom metadata. It also means that view components expose an explicit API to the application.
However, nothing is stopping you from making sure your mediated view components come from the container (and are thus container managed) in the first place, similar to the Swiz approach:
Or, if you don't want to set up a rule for each component:
Of course, that approach would fall down for components that you can not create yourself.
Looking back at it now, I don't like the mediator map hack I proposed. Perhaps extending mediator is the way to go after all - though it could be simpler than you proposed:
I do see the value in being able to inject into mediated view components, I just don't think we can change the behavior in the 1.x branch.
13 Posted by AMo on 03 Oct, 2010 07:44 PM
Hi Shaun,
Thanks for stopping by again and taking the time to read my comments.
I like new proposal of how to better subclass Mediator. That's the elegant solution I was looking for and won't leave me with any niggly feelings if we have to build a large application on top of it. Thanks, much appreciated.
I'll have to think a bit more about your point no. 2.
As for point no.4, I get it: you want views to be completely framework unaware and looseley coupled etc. I think that's a fine goal to aim for in general but it personally wouldn't be that high on my list of priorities for views per se. To clarify, I'm not talking about custom widget type views like calendars, auto-complete text boxes, charting components, menus etc. - these would all naturally be developed with a view to being used just like the native controls i.e. without any dependencies on a particular third-party framework.
Now, we may have had very different experiences and hence disagree on this but my experience has led me to put emphasis on making my models as re-usable and testable as possible. It's not unlikely in my work for the models of an application to be wrapped up in a library/swc and used in diferent applications. After all, you don't want to be re-writing all of the business logic for every new application if the business domain is the same or it's for the same client.
My question is this: RL goes to some lengths to keep views loosely coupled as you've explained but at the very same time advocates that models extend Actor. Yes, I know it's not mandatory to exend Actor but the implication is that you will more than likely be needing to dispatch RL events from your models if you follow RL best practices. In either case, you are building a dependency on RL in your models.
This is another reason why I like utilizing Flex's native bindable/propertyChange mechanisms to notify interested parties/observers (e.g. views, but not limited to) about the current state of a given model - it's not dependent on a third-party framework.
So, in short, how do we achieve the same level of independence for the models that RL advocates for views?
Support Staff 14 Posted by Shaun Smith on 03 Oct, 2010 09:32 PM
Hey AMo,
Indeed, Actor is supplied as a convenience - a quick solution for when you don't mind coupling to the framework. However, I agree that often this is undesirable, in which case (as you hinted at): don't extend Actor. If you need to dispatch events declare a dependency on IEventDispatcher manually:
No framework dependencies, and only uses "standard" metadata. This approach can be used for commands too:
Unfortunately, you can't really get away with not extending Mediator (or MediatorBase).. well, you could but it'd probably be more trouble than it's worth.
Hope that clarifies things a bit. I do often feel that providing Actor was a mistake - and I think I even suggested removing the whole mvcs package at one point, but people felt it would raise the barrier-to-entry significantly for framework beginners.
15 Posted by Nikos on 06 Oct, 2010 09:38 AM
Hi friends,
what advantage does extending Actor have over doing this ?
public class SomeModel
{
}
Also, where is the [Inject] mapping setup in the framework for IEventDispatcher
thanks
Support Staff 16 Posted by Shaun Smith on 06 Oct, 2010 09:46 AM
Hey Nikos,
Extending Actor does not have any real advantages, maybe just some convenience, All the framework bits are mapped into the injector here:
http://github.com/robotlegs/robotlegs-framework/blob/v1.3.0/src/org...
17 Posted by Stray on 06 Oct, 2010 09:51 AM
Why?
18 Posted by Stray on 06 Oct, 2010 10:00 AM
Sorry - that was a Why to Nikos, not a Why to you Shaun.
Interested to know why you wouldn't want to extend Actor, and - more importantly - why you'd want to know where the IEventDispatcher mapping was set up.
19 Posted by Nikos on 06 Oct, 2010 10:00 AM
thanks Shuan, also why does actor need access to the eventMap since extending uses (model,services) don't listen to framework events
Support Staff 20 Posted by Shaun Smith on 06 Oct, 2010 10:07 AM
The EventMap is not just for dealing with framework events - you can use it to keep track of listeners on any event dispatcher.
21 Posted by Nikos on 06 Oct, 2010 10:08 AM
why you'd want to know where the IEventDispatcher mapping was set up.
just out of curiosity mate :)
22 Posted by Stray on 06 Oct, 2010 10:10 AM
Hi Nikos,
I'm sure Shaun will explain further, but the eventMap in Actor is protected, not public.
It's there to allow for the convenience of the eventMap functionality (sugar so that listeners are weak by default, clearing events nicely, checking by class as well as string) to your Models or Services for their internal needs.
For example - in a Service that loads data, you will want to listen to some events on the Loader. Instead of mapping your listeners in the conventional way you can do:
eventMap.mapListener(xmlLoader, Event.COMPLETE, xmlLoaderCompleteHandler);
This doesn't mean you're listening for framework events - you're listening for local events but using eventMap to manage that.
Stray
23 Posted by Nikos on 06 Oct, 2010 10:12 AM
very clever, I keep finding out news things about this genius framework
24 Posted by Stray on 06 Oct, 2010 10:15 AM
>
> why you'd want to know where the IEventDispatcher mapping was set up.
>
> just out of curiosity mate :)
If it's just out of curiosity, have you head of 'find in project'? (Or whatever the equivalent is in which ever IDE you use). ;)
25 Posted by Nikos on 06 Oct, 2010 11:23 AM
so you would do this in the service class
eventMap.mapListener(xmlLoader, Event.COMPLETE, xmlLoaderCompleteHandler);
what advantage does this give you over normal eventlisteners?
Support Staff 26 Posted by Shaun Smith on 06 Oct, 2010 11:52 AM
Yup. Using an EventMap offers 2 advantages:
eventClass
parameter to mapListener events will only pass through to your listener when they are of the correct type:http://github.com/robotlegs/robotlegs-framework/blob/v1.3.0/src/org...
A lot of these kinds of questions can be answered by having a look through the source (or ASDocs):
http://github.com/robotlegs/robotlegs-framework/blob/v1.3.0/src/org...
http://api.robotlegs.org/
The source and ASDocs are also included in the main Download package over at: http://www.robotlegs.org/
The best place to start reading is in the "core" package.
27 Posted by Nikos on 08 Oct, 2010 10:56 AM
2 things:
1
im not sure I really understand this guys:
Modularity: Sometimes you want to mediate a component that lives in a child module without injecting dependencies as configured by the parent - the module might have its own context with its own rules, and injection from the parent would be undesirable.
2
@AMo I wouldn't do this In your mediator you'd have to add listeners to events on all 20 of those fields on the view.
typically I dont care to update the model until the user is finished editing the form, when they click a button then I send all the fields together, saving all the seperate listeners to imitate binding
Stray closed this discussion on 10 Feb, 2011 05:58 PM.