2

I have 2 controllers:

$.Controller('App.Browse',
/** @Static */
{
    defaults : {}
},
/** @Prototype */
{
    init : function(){
        $('#map').app_map();
    },
    // how can I listen here for an event of app_map() controller
})

and

$.Controller('App.Map',
/** @Static */
{
    defaults : {}
},
/** @Prototype */
{
    init : function(){
        // how can I trigger an event to be listened by app_browser() controller
    },
})

The short idea is that while I'm in the App.Map controller I would like to notice the App.Browse controller to do something.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
user1236048
  • 5,542
  • 7
  • 50
  • 87
  • Interesting question. This triggered my curiosity and just been doing a bit of research, I'm sure these will help you http://javascriptmvc.com/docs.html#!jquery.controller.listening and http://forum.javascriptmvc.com/topic/how-to-bind-event-listeners-across-controllers – chridam Oct 11 '12 at 11:57

2 Answers2

2

You could try something along these lines:

window.createEventManager = (function() {

var Event = function(manager, name) {
    this.name = name;
    this._manager = manager;
    this._listeners = [];
};

Event.prototype = {
    listen: function(fn) {
        if (!$.isFunction(fn)) {
            throw "fn is not a function.";
        }

        this._listeners.push(fn);
    },

    fire: function(args) {
        args = args || {};
        args.name = this.name;

        var ls = this._listeners;
        for (var i = 0, l = ls.length; i < l; ++i) {
            ls[i](args);
        }

        this._manager.fire(args);
    }
};


var EventManager = function(eventNames) {
    for (var n in eventNames) {
        this[eventNames[n]] = new Event(this, eventNames[n]);
    }

    this._listeners = [];
};

EventManager.prototype = {
    /**
     * Listen to all events
     * @param fn
     */
    listen: function(fn) {
        if (!$.isFunction(fn)) {
            throw "fn is not a function.";
        }

        this._listeners.push(fn);
    },

    fire: function(args) {
        var ls = this._listeners;
        for (var i = 0, l = ls.length; i < l; ++i) {
            ls[i](args);
        }
    },

    getEvent: function(name){
        return this[name];
    }
};

return function(eventNames) {
    return new EventManager(eventNames);
};
})();

in the map controller:

init : function(){
    events = createEventManager(["mapTrigger"]);
},

and in the browser listen to it by:

  $('#map').app_map().events.getEvent("mapTrigger").listen(function(){
        // Logic to perform on trigger.
  });
AskeG
  • 345
  • 4
  • 14
  • 1
    +1 Your event management code is quite good, but I would argue that splitting listeners in two arrays at group and individual levels is not a good structure. You will have to remember where you are subscribed to, event or manager when unsubscribing. And for unsubscribing from only one or two events when you have subscribed to a manager is not possible without writing logic for it. – maulik13 Oct 19 '12 at 13:28
  • Valid point, I would love to hear your suggestions to a different structure. – AskeG Oct 20 '12 at 14:07
  • How about manager methods addListener and removeListener call the same respective methods on Event objects? May be to simplify the interface and just use EventManager for adding and removing listeners and use those functions on event manager to subscribe to individual or all events. – maulik13 Oct 26 '12 at 18:37
1

JMVC is prepared for that. Just declare it like this:

$.Controller('App.Browse',
/** @Static */
{
    defaults : {
        mapController: null
    },
    listensTo: ['mapCustomEvent']
},
/** @Prototype */
{
    init : function(){
        $('#map').app_map();
    },

    '{mapController} mapCustomEvent': function(element, event, param) {
        //handle event
    }
})

$.Controller('App.Map',
/** @Static */
{
    defaults : {}
},
/** @Prototype */
{
    init : function(){
        param = "something I'd like to pass into event listener";
        $(this).trigger('mapCustomEvent', params);
    }
})

And instantiate:

map = new App.Map('#map');
new App.Browse($('#browse'), {mapController: map});
zaan
  • 887
  • 4
  • 12