MVCS architecture when dealing with keyboard events on a menubar

Matt's Avatar

Matt

05 Sep, 2012 01:29 PM

I have a keyboard driven horizontal menu bar and I'm trying to put together a logical architecture. For now I am just concerned with the menu changing state and not loading anything.

Currently my flow is as follows -

  1. MenuViewMediator dispatches a KEY_DOWN event. For arguments sake, the key pressed is the 'right arrow' key.
  2. The context picks up this event, and launches the command ChangeMenuCommand
  3. ChangeMenuCommand works out which key was pressed, and in turn tells the model to nav right. i.e. menuModel.navRight()
  4. The model attempts to nav right by incrementing an ID that holds the current active item. i.e. currActiveItemID++
  5. The model dispatches a CHANGE_POSITION event with a payload containing the new currActiveItemID
  6. MenuViewMediator is listening for the CHANGE_POSITION event and tells the view to position itself based on the new info. i.e. view.position(currActiveItemID)

Can anyone advise as to whether this is the correct use of MVC?

Some points to consider -

  • ChangeMenuCommand is being used to map a key press to the correct handler. So the right arrow key maps to keyRight() and the enter key maps to keyEnter() etc... etc... Is this the correct place to put this logic? It seems to work well having it in the command.
  • The MenuModel essentially holds state for the menu (storing currActiveItemID and manipulating based on what the command tells it to do). As a result, the MenuModel is dispatching an event when the menu changes state, rather than the MainMenuMediator - is this correct?

I guess I'm just looking for a bit more reassurance that what I'm doing is a good way to do it. Everything seems loosely coupled which is the main goal really.

  1. Support Staff 1 Posted by Ondina D.F. on 05 Sep, 2012 05:51 PM

    Ondina D.F.'s Avatar

    Hey Matt,

    First thought I had:

    Why don’t you let the View manage its own position on the screen in response to a keyDown event, and if you need to store the currActiveItem and the currentPosition in a Model, you can transport that info using a VO, that would be the payload of the event dispatched by the View in the keyDown handler, and then redispatched by the Mediator->Command->Model.

    Do you need to get anything other than what the View should already know, namely its position and currently selected item, from that Model? Or do you just need to trigger other actions, like loading other Views corresponding to the selected menu item?
    Is the re-positioning of the View really dependent on the Model’s data?

    What if you change your mind and you want to have another layout for the menu? Would you use another model, having model.navUp()/model.nav.Down()?

    For now I am just concerned with the menu changing state and not loading anything.

    Usually, it is better to let Views handle their own visual state (like the Flex view states, transitions, show/hide, positioning, etc) internally, and let Models handle application states (the state of the data). Mediators can inform their Views about changes in the application’s state, and if need be, the Views can change their own visual state accordingly. If user interactions with the View affect its state, the best place to handle this is the View itself, and then let the application know about what just happened via events. The View should be pretty self-sufficient and reusable. What if you decide, or need, to use another framework providing another micro-architecture?

    Maybe you have a good reason to have the flow you’ve described, and in this case, yes, it’s the correct flow. You’ll be the one deciding how much View logic you want to put in your Models and Commands. From our previous discussion I know that you like Commands very much ;-)

    Ondina

  2. 2 Posted by Matt on 06 Sep, 2012 10:10 AM

    Matt's Avatar

    Thanks Ondina,

    I guess what I am doing is letting the controller/model decide a lot of the logic that renders the view - which means if the view changes then the model and controllers do too - which is obviously bad.

    The view doesn't need anything else from the model in this case, so I suppose a model isn't even needed here?

    It sounds like I need to move most/all of this logic into the MenuView and handle it there, and only dispatch application events when the selected item changes.

    Thanks,

    Matt

  3. 3 Posted by Matt on 06 Sep, 2012 10:15 AM

    Matt's Avatar

    Can you give me an example of when a MenuModel would be useful? I'm trying to think of situations where you would actually need to manipulate the model based on actions in the view.

  4. Support Staff 4 Posted by Ondina D.F. on 06 Sep, 2012 11:39 AM

    Ondina D.F.'s Avatar

    You’re welcome, Matt!

    I guess what I am doing is letting the controller/model decide a lot of the logic that renders the view - which means if the view changes then the model and controllers do too - which is obviously bad.

    Your intentions are good:) You’re trying to design your application following patterns like single responsibility principle, separation of concerns, loose coupling etc, and that’s a good thing. Defining the roles and responsibilities for the different layers of an application is not an easy task!

    I don’t know how much you already know about robotlegs’ MVCS, but even if you know a lot in theory, looking at examples (with the theory in mind) can be very helpful. Have you seen the long list of demos, examples, and tutorials on our forum? Not all of the examples follow the best practices, but it’s interesting to see how different people use rl and it’s a good source of inspiration.

    Also, Stray’s answers to questions about the roles of Models, Mediators, and other rl actors are an interesting and informative read.
    Here just a short description of rl actors:

    • Services+Models+VOs =responsible for retrieving data, manipulating data, persisting data structures
    • Service = gatekeeper to the outside world, data supplier, data source
    • Model = deals with data, data modeler, responsible for manipulating the application’s states
    • VO=data carrier class to shuttle typed data across tiers
    • Controller=Events+Commands= application logic = application’s behavior= use cases
    • Commands act upon Models and Services, usually in response to user interactions with the application
    • View=user interface
    • Mediator= intermediate, intermediary between application and View, wiring the Views to the shared event dispatcher.

    Services are the intermediaries between an application and the outside world; Mediators are intermediaries between the application and the user interface.

    Sorry if you already knew all this!!

    The view doesn't need anything else from the model in this case, so I suppose a model isn't even needed here?

    Yes, I think that too.

    It sounds like I need to move most/all of this logic into the MenuView and handle it there, and only dispatch application events when the selected item changes.

    Yep, that’s what I would do.

    Can you give me an example of when a MenuModel would be useful? I'm trying to think of situations where you would actually need to manipulate the model based on actions in the view.

    Nothing comes to mind, right offhand. I’ll have to think about it first. I’ll keep you posted.

    Ondina

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

    Ondina D.F.'s Avatar

    https://github.com/joelhooks/robotlegs-examples-AddressBook

    In ContactsView there is a datagrid. You could have a List or a Menu instead.
    Look at ContactsModel, which is used to set datagrid’s dataProvider and to manage datagrid’s selectedItem. ContactsModel dispatches a ContactsModelEvent.SELECTED , ContactsTabNavigator opens ContactForm for the selectedItem.
    Also, follow the flow for saving or deleting an item, which have an impact on the ContactsView as well (a bit similar to what you wanted for your use case, I think)

    Expanding on the MenuView without a MenuModel:
    A custom event could be all you needed to coordinate something like loading of Views ( HomeView, Imagesview, UsersView..) in response to a selected item.
    I guess the use case you’ve presented in our first discussion has something to do with this one, right?
    If so, then NavigatorView, that I was using there as an example, dispatched

    NavigatorEvent.NAVIGATION_INDEX_CHANGED, event.currentTarget.selectedItem

    and in NavigatorModel the selectedItem was just the argument passed to getViewsArray() Bad name, right? Right. And NavigatorModel should be renamed as well, because it’s not really related to navigation, but to creating subviews. In that example NavigatorView’s state is not dependent on NavigatorModel. NavigatorView is model-less:P

  6. 6 Posted by Matt on 07 Sep, 2012 02:48 PM

    Matt's Avatar

    Hi Ondina,

    Thanks again for the response. I'll check out those example demos that you've sent. I've been looking at the Mosaic example but it's quite a different application so not always that useful.

    I've built the menu system to use the methods you suggested above. It feels like a lot of the code is now just in the view but I suppose that's OK.

    Now all the mediator does is dispatch an event to say that the selection has changed. A command picks this up to change the scene.

    I still have a menu model though, which stores the VOs loaded in from the service. Not sure it's really needed though as the VOs could still just live in the view.

    Thanks again for the help.

    Matt

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

    Ondina D.F.'s Avatar

    No problem, Matt.
    The flow you've described sounds about right.
    I’m going to close this discussion. You know what to do: come back with questions about a specific use case (re-open this or create another discussion)

    Cheers,
    Ondina

  8. Ondina D.F. closed this discussion on 07 Sep, 2012 03:03 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