initiating views with a model

iamable's Avatar

iamable

18 May, 2015 01:48 PM

Hey there,

I have a problem with robotlegs 2.
I have a model which holds a list of views.
the model is also instantiating the views.
the model has boolean values for each view and when they are true the corresponding view will be added to the list.
The model has methods to add and remove that views from the list.
When the list changes there will be an event fired with the list of views as payload.
The mediator listens for it and displays the list (unit tested).
Now I want to init that list by setting any boolean value in the model.
But how can I initialize the view with the current list?
when I set the boolean value in the models constructor nothing happens.
I think this is because the model will be configured before the view mediator is mapped.
How can I handle the view initialization (setting any value in the model and the view starts with the right list)

Thanks a lot

  1. Support Staff 1 Posted by Ondina D.F. on 19 May, 2015 09:42 AM

    Ondina D.F.'s Avatar

    Hi,

    What you're experiencing is called a "race condition".

    I think this is because the model will be configured before the view mediator is mapped.

    Or before the mediator is created and ready to react to events.

    I can't draw a schematic representation of the workflow you've described, but, I hope that you'll get the idea:

    1 ----model mapping--------------view/mediator mapping

    2 ----model instantiation

    3 ---model dispatches event---------------> ** mediator can't 'hear' the event**

    4 ----view added to stage triggers--------->mediator creation

    5 ----mediator initialization

    6 ----mediator adds event listener for model's event

    7 --- nothing happens

    You have to make sure that the mediator has already added an event listener for the event before the model dispatches the event.
    Without knowing more about your use case, I'd say that you should let the mediator add an event listener for a model event, let's call it LIST_UPDATED, within its initialize() method, then dispatch an event to request data from the model, LIST_DATA_REQUESTED, that will trigger a command, that has been injected with the model. The command accesses a method of the model, and the model dispatches the LIST_UPDATED event when it is done. The mediator is now able to handle the event. Important: first add a listener, then dispatch the requesting event!

    The above becomes this:

    1 ----model mapping--------------view/mediator mapping

    2 ----view added to stage triggers--------->mediator creation

    3 ----mediator initialization

    4 ----mediator adds event listener for model's event

    5 ----mediator dispatches an event to request the list---->a command accesses the model's API

    6 ----model dispatches event---->mediator handles the event

    Or, you can use the RelaxedEventMap extension:

    https://github.com/robotlegs/robotlegs-extension-RelaxedEventMap

    Doing work in the constructor of the model is not a good idea. Take a look at this:

    https://github.com/robotlegs/robotlegs-framework/wiki/Common-Proble...

    the model is also instantiating the views.

    Do you really need to do that in the Model? That's usually the responsibility of the View.

    Hope this helps.
    Ondina

  2. 2 Posted by iamable on 20 May, 2015 05:16 AM

    iamable's Avatar

    Hey Ondina,

    thanks for your reply and your detailed explenations :)
    I understand the process for initializing views with model data.
    Is there a possibility to have an event fired when all views are added to the stage?
    I just want one single initialization command executed and not one command for every single view when it is added to the stage

    regarding the instantiation of the views within the model.
    I am doing this because I wanted to give the list view only the data it needs.
    The calculation which list element will be displayed is done in the model.
    How would you do that? How can the model handle the list items (sprites) without instantiating them?

  3. Support Staff 3 Posted by Ondina D.F. on 21 May, 2015 10:55 AM

    Ondina D.F.'s Avatar

    Hey,

    How would you do that? How can the model handle the list items (sprites) without instantiating them?

    Hehe, now I'm sorry I've touched that subject at all.
    There is no 'one size fits all' solution.
    I hope that you're aware of the fact that I cannot answer such a question without knowing a lot more about your application. But even if I knew more, finding the best solution would be time consuming (for me).

    From the little I know about your project, I'd say that your use case would benefit from using the Factory pattern. Probably that was somehow your intention. A ViewFactory class could be used in a command, or, better, directly in the view that needs the subviews. For the latter, you'd inject the factory into the mediator and pass it to the view.

    Take a look at Factory pattern, Fluent builders, Builder pattern, Fluent interface

    Now I see that you added a new question to your message:

    Is there a possibility to have an event fired when all views are added to the stage?

    I'm sorry, but I don't get it. I don't understand the nature of your list. When I hear "List", I think of a collection of items, like in a Menu, usually as strings. It seems that you are talking about components added to a parent view and you use the term list like in the "display list" ?

    If you added the subviews directly in your parent view, you could of course know when all suvviews were added to the stage. But you're adding them in your model....
    Are the views that you're manipulating in your model modules that you're loading somewhere else?

    I just want one single initialization command executed and not one command for every single view when it is added to the stage

    That's of course possible too, but I don't understand the workflow, so I cannot answer this either.

    the model has boolean values for each view and when they are true the corresponding view will be added to the list.

    On what condition it becomes true?

  4. 4 Posted by iamable on 21 May, 2015 11:26 AM

    iamable's Avatar

    OK sorry let me explain the applications flow.

    There is a service receiving data from somewhere.
    Lets say there are messages coming in like redLight = false, yellowLight = true, blueLight = false, greenLight = true.
    Now I want to have a display list with components which corresponding signal is true.
    So I have components called redLightView, yellowLightView, ...
    All the components are extending a LightView and passing their color to the super class.

    My idea was to make the mapping of incoming light signals to views in the model.
    The model has all extended LightViews instatiated.
    If this value of the signal changes the corresponding view will be added or removed to/from an array. whenever that array changed an event will be fired with the array as payload. The mediator of the listview listens for it and triggers refreshing the display list.

    I thought the view shouldn't have more calculation than it needs for displaying things. And I thought the array itself is more a data base than view calculation.
    I think it is not the best way to make the calculation of adding and removing elements in the array within the list view, isn't it?

    I will have a look at Factory pattern.
    I hope we will find a good solution.

    Thank you

  5. 5 Posted by iamable on 21 May, 2015 01:04 PM

    iamable's Avatar

    Hey Ondina,

    I'd just change my architecure:

    adding and removing extended LightViews has moved to the display list view.
    No I'm instatiating the Light Views in that display list view.
    The mediator of that display list handles the events for changing singals.

    Now I don't understand where the factory pattern could play any role.
    In addition I don't like the mediator is knowing all the Light views within the list view and triggers them to add/remove to/from the list. I think this could be a point to use the factory pattern, right?
    The problem is I doesn't really understand how to use it in this case.

  6. Support Staff 6 Posted by Ondina D.F. on 21 May, 2015 05:04 PM

    Ondina D.F.'s Avatar

    Thanks for providing more details:)

    It's evening where I live, so I'll answer your questions tomorrow as soon as I get a chance.

  7. Support Staff 7 Posted by Ondina D.F. on 22 May, 2015 10:40 AM

    Ondina D.F.'s Avatar

    Your workflow + Factory:

    At some point in time the model, I'll call it LightsModel, receives data from a service call and stores it in a collection, where redLight=true, greenLight=false, etc

    The LightsHolderView (I can't come up with a better name right now) is added to the stage.

    A LightsFactory has been mapped asSingleton and was injected into LightsHolderMediator, and passed to the view in its initialize() method:

    view.lightsFactory = lightsFactory; //the injected one

    LightsHolderMediator also adds the event listener mentioned in the previous posts, and dispatches an event to request data from the LightsModel from within the initialize() method.

    LightsModel sends the dictionary with red=true, green=false, etc.

    LightsHolderMediator passes the payload of the event to the LightsHolderView, say

    view.lightsDataChanged(event.payload);

    Within lightsDataChanged, the view iterates through the collection and for each true value it adds a LightView to its stage. Something like this:

    public function lightsDataChanged (lights:Dictionary):void
    {
        for(var lightColor:String in lights)
        {
            if(lights[lightColor]==true)
            {
                addChild(_lightFactory.createView(lightColor));
            }
        }
    }
    

    Of course you can also remove views. This is just pseudocode for the sake of an example.

    The LightsFactory can hold a lightDictionary, where greenLight, redLight, yellowLight..etc, are the keys and GreenLightView, RedLightView are the values, as classes. ( lightDictionary["greenLight"] = GreenLightView; )

    public function createView(lightColor:String): ILightView
    {
        return new lightDictionary[lightColor]();
    }
    

    When you're done with adding/removing subviews, you can of course dispatch an event for the mediator to hear and do whatever it needs to be done.

    The LightsModel is now concerned only with the data and the state of that data. What happens if greenLight is true or false is not Model's concern anymore. A View (or more views and other classes) could react to that info in different ways, some by drawing green circles, others by drawing green squares, or by playing some music and so on. A lot can happen inside an application because the greenLight==true;)

    Of course you can hold a dictionary of colors/view classes (not instantiated) in the model itself or in a VO, that would be sent to the mediator/view. In this case you don't need a factory. The view just iterates through the dictionary, instantiates the subviews and adds/removes them accordingly. This kind of model is surely not as 'clean' as the one above, but sometimes it might be useful.

    In addition I don't like the mediator is knowing all the Light views within the list view and triggers them to add/remove to/from the list. I think this could be a point to use the factory pattern, right?

    You're right, LightsHolderMediator shouldn't have to know about the children of LightsHolderView, be it a GreenLightView or a PinkLightView or a VariegatedView.

    The LightsHolderMediator is just passing the data from the model to the view.

    I thought the view shouldn't have more calculation than it needs for displaying things. And I thought the array itself is more a data base than view calculation.

    What do you mean by "calculation"? The decision which view to add or to remove?
    In my example, the decision has been made in the model (greeen=false, red=true), and the view is just "reading the directives" in a loop and does its job.

    On another note, you might have a good reason to have a RedLightView, a YellowLightView, etc, but it sounds to me like the only thing that differentiates them is the color. If so, then you only need one Class, LightView implementing a ILightView with a set color method.

    Here is an example of a factory:

    https://github.com/Stray/robotlegs-examples-OreillyBook/blob/master...

    Are things more clear now?

  8. Ondina D.F. closed this discussion on 01 Jul, 2015 06:41 AM.

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