Keeping injected model objects in sync between modules

jeremy.brooks's Avatar

jeremy.brooks

06 Sep, 2012 08:39 AM

Hi all,

How do you keep all injected model objects in sync without having to pass them between modules using custom events?

info: I'm using RL 1.5.2 and the modular utility library.

Thanks,
Jeremy.

  1. 1 Posted by neil on 06 Sep, 2012 10:02 AM

    neil's Avatar

    There are a lot of ambiguities in your question.
    Can you be more specific?
    If modules are sharing models, then they should use the same model.
    An injected actor will be available in all child injectors (modules), so if your root injector has an instance mapped against IActor then it will be available to all its children.

  2. Support Staff 2 Posted by Ondina D.F. on 06 Sep, 2012 10:27 AM

    Ondina D.F.'s Avatar

    Hi Jeremy,

    How do you keep all injected model objects in sync without having to pass them between modules using custom events?

    You don’t need to pass the Models between Modules. The Models, or a Command that’s accessing them, can dispatch an event on the module dispatcher when the data changes, with or without the data as a payload.

    I see 2 solutions, in theory (you’ll have to try them out):

    • In the Context of each module, ModuleOne and ModuleTwo, you map a SharedModel. In SharedModel, when you set someSharedData in one of the modules, you dispatch a SharedEvent:

    moduleDispatcher.dispatchEvent(new SharedEvent (SharedEvent.SOME_DATA_CHANGED, someSharedData));

    For that to happen, you need the module dispatcher inside of your model:
    [Inject] public var moduleDispatcher:IModuleEventDispatcher;

    ModuleOne and ModuleTwo add event listeners for SharedEvent.SOME_DATA_CHANGED in the classes that need to be notified about the changed Model’s data.

    • you map a SharedCommand and a SharedModel in your shell’s Context. Instead of injecting the SharedModel into your modules you let the modules dispatch an event that would trigger a SharedCommand, that in turn would access the SharedModel, and either SharedModel or SharedCommand would dispatch the SharedEvent to the modules, with or without a payload.

    Ondina

    P.S. I see Neil answered while I was still writing, though I’ll add my 2 cents;)

  3. 3 Posted by jeremy.brooks on 06 Sep, 2012 12:53 PM

    jeremy.brooks's Avatar

    Thanks for the replies guys, some good advice and I'm currently going through my code to try out your suggestions.

    @Neil: I haven't extended Actor or MuduleActor for my models as I'm not currently dispatching any events from them, and I thought that was the only time I needed to extend Actor, have I missed a trick? Does the injector rely on models extending Actor to inject correctly?

    Thanks,
    J.

  4. 4 Posted by neil on 06 Sep, 2012 12:55 PM

    neil's Avatar

    Sorry, I was using the word Actor to mean "an actor in the system" as opposed to any Concrete impl.

  5. 5 Posted by jeremy.brooks on 06 Sep, 2012 12:59 PM

    jeremy.brooks's Avatar

    Ah I see, no worries Neil, you can see where I got crossed wires. You'll laugh at this, I was trying to find IActor for a few minutes there and wondering why I wasn't getting an auto complete haha!

  6. 6 Posted by jeremy.brooks on 06 Sep, 2012 01:37 PM

    jeremy.brooks's Avatar

    I'm currently using a solution that's not far off Ondina's option 1 except the model doesn't dispatch events. I have a main "control" module that loads other modules. This main module has the following mapping in its context:

    injector.mapSingletonOf(IModelObject, ModelObject);

    This mapping works fine, when I get to my first command that injects this model object its ok, I populate it a little, then my command dispatchToModules an event to let other modules know the model has changed, and I provide the model object as a parameter.

    The event is successfully heard in the other modules, at which point I do a manual injection using the following syntax from within a command for those modules:

    injector.mapValue(IModelObject, event.modelObject);

    This also works fine, and further injections of the object is fine for those modules. However when it comes to the main module injecting that model object it seems to create a fresh instance again, and ignore the original instance it created on first injection.

    Any thoughts?

  7. 7 Posted by jeremy.brooks on 06 Sep, 2012 02:06 PM

    jeremy.brooks's Avatar

    Right got to the bottom of this, I was instantiating the object being injected after injection, meaning I was not changing the mapped object but a new instance instead, I forgot the basic fundamentals of injection.

    Although this still doesn't answer my question as to how to share an injected model between modules without some form of event dispatching. I'll just settle for using events for now i guess. I was just hoping for some kind of module injector, but never mind.

  8. Support Staff 8 Posted by Ondina D.F. on 06 Sep, 2012 02:15 PM

    Ondina D.F.'s Avatar

    Jeremy, you can access the model from each module, but without dispatching an event from the model, how would you know when its data changed?

  9. 9 Posted by neil on 06 Sep, 2012 02:19 PM

    neil's Avatar

    @Ondina I believe he is dispatching an event separately from the model, after it has been altered.

    what advantages do you gain from separating the event dispatching from the model?

  10. Support Staff 10 Posted by Ondina D.F. on 06 Sep, 2012 02:21 PM

    Ondina D.F.'s Avatar

    @Neil ah, ok

  11. 11 Posted by jeremy.brooks on 06 Sep, 2012 02:30 PM

    jeremy.brooks's Avatar

    Well it just felt like a nice idea to let the model hold its state and not worry about notification, all my event dispatching is handled by the command that alters model state. Not sure if its an advantage or not, its just a personal thing, and to be honest, throughout development I've changed stance back and forth several times.

  12. 12 Posted by jeremy.brooks on 06 Sep, 2012 02:37 PM

    jeremy.brooks's Avatar

    @Ondina You are correct of course, you can access the model from each module, but you still have to inject an instance of that model, and handle changes to it between modules. With a non modular application, you don't need to worry about this, because the injector always injects the same instance. Now if we had a "moduleInjector" that did the same thing for modules, that would be cool.

  13. Support Staff 13 Posted by Ondina D.F. on 06 Sep, 2012 02:57 PM

    Ondina D.F.'s Avatar

    Not sure, but maybe the links to Stray’s answers from this response is what you want to achieve?
    http://knowledge.robotlegs.org/discussions/questions/983-sharing-mo...

  14. 14 Posted by neil on 06 Sep, 2012 03:15 PM

    neil's Avatar

    How are you creating your modules?
    If each module has a child injector of the main injector, then the mappings from the main injector will be available in each module

  15. 15 Posted by jeremy.brooks on 06 Sep, 2012 03:29 PM

    jeremy.brooks's Avatar

    @Neil Here is a code snippet from my module that I use to load other modules:

    <mx:Module xmlns:mx="http://www.adobe.com/2006/mxml"
               implements="org.robotlegs.utilities.modular.core.IModule"
               layout="absolute">
        <mx:Script>
            <![CDATA[
                import org.robotlegs.core.IInjector;
                import org.robotlegs.utilities.modular.core.IModuleContext;
                
                import uk.module.context.ModuleShellContext;
                
                private var context:IModuleContext;
                
                [Inject]
                public function set parentInjector(value:IInjector):void{
                    context = new ModuleShellContext(this, true, value);
                }
                
                public function dispose():void{
                    context = null;
                }
            ]]>
        </mx:Script>
    </mx:Module>
    

    and here is a code snippet from one of the modules that is loaded by the main module:

    <mx:Module xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:mx="library://ns.adobe.com/flex/mx"
               implements="org.robotlegs.utilities.modular.core.IModule"
               layout="absolute"
               width="100%"
               height="100%"
               xmlns:view="uk.view.*">
        <fx:Script>
            <![CDATA[
                import org.robotlegs.core.IInjector;
                import org.robotlegs.utilities.modular.core.IModuleContext;
                
                import uk.module.context.ModuleContext;
                private var _context:IModuleContext;
                
                [Inject]
                public function set parentInjector(value:IInjector):void{
                    _context = new ModuleContext(this, true, value, ApplicationDomain.currentDomain);
                }
                
                public function dispose():void{
                    _context = null;
                }
            ]]>
        </fx:Script>
        <view:View id="map" width="100%" height="100%"/>
    </mx:Module>
    
  16. 16 Posted by neil on 06 Sep, 2012 03:35 PM

    neil's Avatar

    so your IModelObject injected as a singleton into your main module (shell)
    should be available to inject in your sub modules

    [Inject] public var model:IModelObject;

    if its not, something is wrong.
    (take a look at all those links Ondina posted, and click thro to stray's comments)

  17. Support Staff 17 Posted by Ondina D.F. on 07 Sep, 2012 03:13 PM

    Ondina D.F.'s Avatar

    Sorry guys, I have to close the discussion (incoming spam is increasing). You can re-open it if you want to continue this discussion.

  18. Ondina D.F. closed this discussion on 07 Sep, 2012 03:13 PM.

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