Basic MVC Question

I have a button in a toolbar that I want the "ontap" dispatched to a controller. I thought something like this would work:

(this is just the button in the menu, I've omitted the surrounding)
{classes: "icon menu", controller: ".app.controllers.menu" ontap: "showMenu"}
... where showMenu is a function in my controller. But it's not working. The only way I can get it to work is to add an "ontap" function to my controller, but then the controller can only listen to one ontap for the entire application. I'm sure there's something basic I'm missing.

Eric

Comments

  • In your ontap handler, look at the inSender argument to see who send the tap and do different things. You might also find inEvent.originator useful, since inSender is the most recent dispatcher, not the original one.
  • Thanks - the problem is that I'm not getting the event to fire in my controller at all. I looked through the code and noticed that when a component declares an event hander, that it will walk through it's hierarchy looking for a function matching the name... but it doesn't appear to look in the declared controller.

    To provide a concrete example:

    This works... the parentComponent function is invoked on tap

    {name: "parentComponent", myTapHandlerFunction: function() {...}, components: [
    {name: "childComponent", ontap: "myTapHandlerFunction"}
    ]}
    This also works. The "ontap" function in myController is invoked when myComponent is tapped:

    {name: "myController", ontap: function() {...}}

    ...

    {name: "myComponent", controller: ".app.controllers.myController"}
    but this doesn't work:

    {name: "myController", myTapHandler: function() {...}}

    ...

    {name: "myComponent", controller: ".app.controllers.myController", ontap: "myTapHandler"}

    It's possible that it shouldn't work - but it seemed logical to me. I'm trying to have one Controller that handles tap events for multiple components.

    Thanks,
    Eric
  • As far as I know, controllers only support the handlers block to intercept events, they don't support have a event handler named in the sender instance. When you name an event handler in the instance, that's only used to look in the owner of the instance, not anywhere else.
  • OK, that makes sense why it's not working...

    IMHO, this would be a great addition - if an instance has bindings to a controller, to look to the controller in addition to the owner for event handlers. This lets a controller more effectively sit on top of a number of components, and lets the components have more control over how their events are handled.
  • edited August 2013
    i would recommend using BubbleUp for this purpose. If using a ViewController, the bubble target of the view is the controller. This gives you the freedom to handle the event in the view for visual changes, and in the controller for logic changes. Bubbleup is a super powerful tool to do the kinds of things you elude to.

    For example, the view has a button with this code:
    
    kind: 'Button', 
    content: 'Export Data',				
    handlers: {
         ontap: 'callexport'
    },
    callexport: function () {
        this.bubbleUp('onexport');
    }
    
    The controller has this code:
    
    handlers: {
        onexport: 'getPathForExport',
    },
    getPathForExport: function () {
        ..do export....
        return true  //to stop propogation
    },
    
  • Also, don't forget Signals. If you want to invoke events outside the component hierarchy, you can always use Signals to radio them out.
  • dposin -

    Thanks for the example. I can see how bubbling allows you to bind behavior of a component to the controller... I'm just proposing that the handlers are overly ceremonious. Similarly, it would be tedious if you had to declare handlers and manually bubble each time you wanted a component's owner to handle the event. I guess technically you could add the Controller into your component hierarchy to achieve the same effect.

    To me, controllers are an injected owner - they broker data for a view (bindings), and handle users interactions with the view. Also, because they contain the model that backs a view, that makes them an even better candidate for handling events.

    One other thought: I think it would be nice to be able to "mount" a controller at the top of a complex component, and have all the events and bindings inside the component tree bubble up to it (without having to explicitly declare it in your bindings). That way, it's very trivial to have a ModelController that contains an object at the top, and the nested "Delete" button at the bottom can very simply propagate up to the controller. Similarly, if you have components that are nested, they could easily bind "upwards" to the data from the controller without having to explicitly declare it. Currently, it's very difficult to do because the controller isn't anywhere in the "owner" hierarchy.

    These are just my opinions - and I come from a different world than enyo, so it's very probably (likely) that I will change my mind as I learn more. But that's the way I see it at the moment. Thanks again.
  • edited August 2013
    I am came across much of what you mention above and don't disagree. I found that having the controller separated from the view problematic as well. My first thought is you should explore the components block. The components will let you make that inheritance tree.

    As far as having the controller be the owner, I forced that relationship and found it helped. Just being able to call this.view was amazing. I have the application "view" set to an empty object, and turned renderOnStart to false. I connect only a router controller to the app. Inside, the router I call a new instance of the appropriate controller and render it into a div.

    The hierarchical result is:

    Application --> Router --> Business Logic Controller --> View

    Would that help meet your needs?
Sign In or Register to comment.