Modularity

oleg3000's Avatar

oleg3000

27 Apr, 2017 04:16 PM

Hi! I've got a problem:
I've got 2 contexts with same mediator-view mapping, the second context view lays inside the first. It looks like:

Container
|--ContextView1
    |--ContextView2

I use StageObserverExtension and I do need it, the problem is that when I'm trying to add a View to ContextView2 StageObserver handles addedToStage event and instantiates Mediator set for Context1. Can I avoid it somehow? So I want Context2 views not to be handled by Context1's StageObserver.
Thanks!

  1. Support Staff 1 Posted by Ondina D.F. on 28 Apr, 2017 12:11 PM

    Ondina D.F.'s Avatar

    Hi Oleg,

    If you take a look at the StageObserverExtension, you can see that there is a single instance of the StageObserver being used throughout the life cycle of an application:

    "The Stage Observer Extension adds a single instance. Which listens for everything that is Event.ADDED_TO_STAGE on all root containers in the Container Registry, and then processes the view for you."

    StageObserverExtension

    https://github.com/robotlegs/robotlegs-framework/blob/master/src/ro...

    https://github.com/robotlegs/robotlegs-framework/blob/master/src/ro...

    StageObserver:
    https://github.com/robotlegs/robotlegs-framework/blob/master/src/ro...

    Now, take a look at the ModularityExtension:

    https://github.com/robotlegs/robotlegs-framework/tree/master/src/ro...

    The first parameter, inherit: Should this context inherit dependencies from a parent context?

    Usually, when you want to add a view, say SimpleView to ContextView1 and also another instance of SimpleView to ContextView2, and they should have different mediators, you need to create 2 mappings:

    One in you ContextView1 - config:

    mediatorMap.map(SimpleView).toMediator(SimpleMediator);

    And another in your ContextView2 -config :

    mediatorMap.map(SimpleView).toMediator(SimpleMediator);

    You set "inherit" to false when you install the ModularityExtension in your child context:

    .install(new ModularityExtension(false, false))

    And now, each context will handle SimpleView through the correspondingly mapped mediator.

    You said:" I use StageObserverExtension and I do need it ".
    Does that mean that you can't use a mapping like in my example above?

    I hope that helps. Let me know if it doesn't, and provide more details about how you are using the StageObserver.

    Ondina

  2. 2 Posted by oleg3000 on 29 Apr, 2017 11:08 AM

    oleg3000's Avatar

    Hi Ondina, thank you so much for helping me!
    Yes I use mapping like in your example and the problem is that StageObserver listens to ContextView1 ADDED_TO_STAGE events in capture phase
    https://github.com/robotlegs/robotlegs-framework/blob/master/src/robotlegs/bender/extensions/viewManager/impl/StageObserver.as#L83
    , so all ADDED_TO_STAGE events of ContextView2 children will also be handled as ContextView2 is parent of ContextView1. So then SimpleView added to ContextView2 will be handled by Context1 StageObserver.
    Looks like the only work-around here is to listen to ContextView2 ADDED_TO_STAGE event in capture phase with higher priority and call stopPropagation() in case ContextView2.contains(event.target) .
    I tried Modularity with false,false but It haven't helped. As I understand this extension is only responsible for sharing injector between contexts.

  3. Support Staff 3 Posted by Ondina D.F. on 29 Apr, 2017 05:20 PM

    Ondina D.F.'s Avatar

    You're welcome, Oleg!

    So then SimpleView added to ContextView2 will be handled by Context1 StageObserver.

    There is only one StageObserver! So, yes, SimpleView will be handled by the same StageObserver, in Context1 and in Context2. But you shouldn't be concerned about the internal working of the framework as long as you are configuring your contexts correctly.

    Do I understand you correctly that you are using the StageObserver directly in your code to manage your views? If so, why do you need to do that?

    As I understand this extension is only responsible for sharing injector between contexts.

    ...and mappings, and/or create child-injectors and mappings

    "The ModularityExtension allows a context to inherit dependencies from a parent context, and/or expose its dependencies to child contexts."

    dependencies==mappings

    I tried Modularity with false,false but It haven't helped.

    That works for sure. Without seeing your code I can't say why it doesn't work for you. Would it be possible to show your configs and mappings for the 2 contexts or to attach a simple example illustrating your use case?

    Could it be that you are using the same MVCBundle for both contexts?

    You can see an example of using the ModularityExtension with different settings:

    http://knowledge.robotlegs.org/discussions/robotlegs-2/6915-best-pr...

    At the end of the answer there is an attachment that you can download. (ondina-robotlegs-bender-shared-configs ) It is an air application.

    And at the end of this message you'll find an example based on the one above, but having just one child context.

    You can add SimpleView to the RootContextView
    You can add a ChildContextView to the RootContextView
    You can add SimpleView to ChildContextView

    SimpleMediator is mapped to SimpleView, first inside of RootRobotlegsContext -> MediatorsConfig

    and then inside of ChildRobotlegsContext -> ChildContextMediatorsConfig

    ChildRobotlegsContext uses a custom MVCSBundle: MVCSBundleTwo where ModularityExtension(false, false)

    Look at the traces inside of SimpleMediator and see how each SimpleView is communicating only with the mapped mediator.

    Just in case you need to know more about modularity and inter-modular communication:

    https://github.com/Ondina/robotlegs-bender-modular-air

    https://github.com/Ondina/robotlegs-bender-as3-modular-example

    Let me know how it goes.

  4. 4 Posted by oleg3000 on 02 May, 2017 06:28 AM

    oleg3000's Avatar

    Do I understand you correctly that you are using the StageObserver directly in your code to manage your views? If so, why do you need to do that?

    I use StageObserverExtension

    Could it be that you are using the same MVCBundle for both contexts?

    Different MVCSBundles, but same mediator-view mapping

    Would it be possible to show your configs and mappings for the 2 contexts or to attach a simple example illustrating your use case?

    Sure, I've changed your example a little https://www.sendspace.com/file/7x1gvv

  5. Support Staff 5 Posted by Ondina D.F. on 02 May, 2017 03:00 PM

    Ondina D.F.'s Avatar

    I use StageObserverExtension

    Yeah, but the only purpose of StageObserverExtension is to instantiate StageObserver once.

    I still don't understand how you use the extension, because the modified example that you've attached is just adding a simple child-context to the root-context.
    Also, I don't understand why you need to map SomeView in the root-context and in the child-context. If you don't want the root-context to react to SomeView being added to the stage, you don't create a mapping for it in the root-context.
    If you could explain your use case, as in what you want to achieve by having 2 mappings, I might be able to help you. Otherwise I'll just keep guessing different scenarios ;)

    In the example I've attached to my previous answer (ondina_simple_child_context) there is a SimpleView added to the root-context and another SimpleView added to the child-context. Each instance has its own mediator.

  6. 6 Posted by oleg3000 on 02 May, 2017 03:41 PM

    oleg3000's Avatar

    Also, I don't understand why you need to map SomeView in the root-context and in the child-context. If you don't want the root-context to react to SomeView being added to the stage, you don't create a mapping for it in the root-context.

    Will try to explain
    The project1 contains from A,B,C Views. I want to have a (lets call it widget) widget1 which is actually a copy of project1, but it contains C View only. What do I want is to be able to add that widget1 into the project1 (as a child in view tree), thats why I have same CMediator-CView mappings(I assume contexts are isolated so I define the mapping for both contexts).
    In the example I sent I added mediatorMap.map(SomeView).toMediator(SomeMediator);
    mapping to the shell's MediatorConfig, so both child and parent context has got that mapping. When you try to add SomeView to child context - you'll see in logs that SomeMediator is initialized 2 times, so I want to completely isolate child context from the parent one.
    In other words, roughly, I'd like to add a copy of Application inside itself, that's why I want to be able to isolate these contexts.

  7. Support Staff 7 Posted by Ondina D.F. on 02 May, 2017 04:52 PM

    Ondina D.F.'s Avatar

    When you try to add SomeView to child context - you'll see in logs that SomeMediator is initialized 2 times, so I want to completely isolate child context from the parent one.

    In the modified example that you added you did not add SomeView to child context.
    SomeView IS the view used to build the child context!!!
    Each context has a VIEW: the root context (ShellMainView) and the child context (SomeView)

    Did you take a look at the example I attached to this discussion? The zip file at the end of my second answer to you?? It's called ondina_simple_child_context .zip
    There you can see exactly what you're describing. SimpleView is something like your CView, it can be added to the root-context and to the child-context, as well.
    In my example, RootContextView is adding a ChildContextView and a SimpleView. ChildContextView is also adding a SimpleView. The 2 SimpleViews are "isolated" from each other. The SimpleView has a mapping for the root and another for the child context.

    Take a look at the example and let me know why is not a good solution for you.

  8. 8 Posted by oleg3000 on 11 May, 2017 11:18 AM

    oleg3000's Avatar

    Hi Ondina,
    I've checked your example - it actually doesn't create second context, as group1_creationCompleteHandler seems to be never called.

    I have changed your example a bit to show how to reproduce the issue, what did I do:

    • Added creationComplete listener to trigger group1_creationCompleteHandler

    • Added missing interface implementation " implements IConfig" to ChildContextMediatorsConfig and added this config into ChildRobotlegsContext

    • Added .initialize() call to both contexts

    After that you'll se 2 SimpleMediator.initialize() calls in log

  9. 9 Posted by oleg3000 on 11 May, 2017 02:25 PM

    oleg3000's Avatar

    Changed example in attachment:

  10. Support Staff 10 Posted by Ondina D.F. on 12 May, 2017 11:10 AM

    Ondina D.F.'s Avatar

    Hi Oleg,

    First of all, I can't download your modified example. The zip file seems to be corrupted.

    You are right, I made a mistake. I forgot to add the FlexEvent.CREATION_COMPLETE inside of the ChildContextView and the ChildContextMediatorsConfig implements IConfig thing! It probably happened because I first changed my original example (robotlegs-bender-shared-configs) to illustrate the simple_child_context case, but then I decided to create a new project just for that matter. I was in a hurry when I copied and pasted configurations from one project into another and some things got lost on the way...;)

    Sorry for that and thanks for the corrections you've made.

    Added .initialize() call to both contexts

    That's not needed!!

    The contexts will be initialized just fine, because they both have a context view.

    See here:
    https://github.com/robotlegs/robotlegs-framework#context-initializa...

    So, is now everything working as you want it to work? Is your initial problem solved?

  11. Support Staff 11 Posted by Ondina D.F. on 12 May, 2017 02:09 PM

    Ondina D.F.'s Avatar

    I've got a few minutes to run the corrected example and now I see what you meant. I don't know yet why it's happening. I don't have time right now to look into it. I'll try to find time for this over the week-end or next week.

  12. 12 Posted by oleg3000 on 12 May, 2017 02:25 PM

    oleg3000's Avatar

    This is happening because there is a parent binding assigned by default for ChildContext
    https://github.com/robotlegs/robotlegs-framework/blob/master/src/ro...

    And then StageObserver triggers all bindings to handle ADDED_TO_STAGE
    https://github.com/robotlegs/robotlegs-framework/blob/master/src/ro...

    I've temporary applied such a crutch, so it works:
    containerRegistry.getBinding(contextView.view).parent = null;

    Will consider you idea to not to trigger .initialize() seems like this method creates that binding, but project doesn't work properly without it - will get back later when I know if it possible to not to use .initialize()

    Thank you again for support!

  13. Support Staff 13 Posted by Ondina D.F. on 13 May, 2017 04:51 PM

    Ondina D.F.'s Avatar

    This is happening because there is a parent binding assigned by default for ChildContext

    Yep. You're right!

    I've temporary applied such a crutch, so it works:

    If it works for you, go for it, but I think that you somehow could avoid such workarounds.

    I've modified my example, again. Hopefully this time without omissions of any kind:)
    I hope you'll understand what's going on in spite of the ugly layout.
    In this version there are:

    • RootContextView - root context

    • ChildContextView with its own context - mediator mapped only in the child context

    • SharedContextView with its own context - mediator mapped only in the shared context

    • SimpleView - just a simple component with a mediator mapped only in the root context

    So, one hierarchical combination could be:

    --- RootContext

    ------ChildContext

    --------- SharedContext

    -------------- SimpleView

    Or:
    --- RootContext

    --------- SharedContext

    -------------- SimpleView

    or:
    --- RootContext

    ------ChildContext

    -------------- SimpleView

    Since SimpleView does not have its own context, it has been mapped only inside of the root context. Only one new mediator would be created when an instance of SimpleView is added to one of the 3 context-views. So, each instance added to the stage will have its own mediator ( no duplicates).

    SharedContext and ChildContext have their own context and mappings. There is no need to map them inside of RootContext as well!

    I put SharedContext and SimpleView inside of the commons folder. They could as well be inside of a library of "widgets" or reusable components.

    The project1 contains from A,B,C Views. I want to have a (lets call it widget) widget1 which is actually a copy of project1, but it contains C View only. What do I want is to be able to add that widget1 into the project1 (as a child in view tree),

    If RootContextView is what you call project1, I still don't understand why you want to add a copy of RootContextView to itself.
    Anyway, obviously you'll have to map CMediator-CView only once in the root context.

Reply to this discussion

Internal reply

Formatting help / Preview (switch to plain text) No formatting (switch to Markdown)

Attaching KB article:

»

Attached Files

You can attach files up to 10MB

If you don't have an account yet, we need to confirm you're human and not a machine trying to post spam.

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