Search code examples
javascriptbackbone.jsbackbone-events

Get return value from a Backbone event listener callback function


I have a function (getHealth) in one js file LoadSolutionView to return a percentage.

In another JS file as an entry point on page load where I have an event listener for this function as follows

function getHealth(dow) {
        Main.Views.LoadSolutionView.getHealth(dow);
}
Main.EventAggregator.listenTo(Main.Views.OverviewView, 'getHealth', getHealth);

In my OverviewView file, I have the following function that triggers the getHealth function successfully but I do not get the returned value, instead I get all childs of this. Is there a means of getting the returned value from triggering the getHealth function?

saveRooms: function(dayId, solutionId, shiftId, day) {
    var self = this;

    var roomIds = self.getIds('roomsEdit');
    roomIds = _.map(roomIds, Number);

    this.trigger('editShiftDay', this.solution, this.dto, this.numDays, this.endDate, solutionId, dayId, day);

    var percentage = this.trigger('getHealth', dayId);

    this.hideOptions();

    this.checkForChanges();
},

Solution

  • The Backbone Events trigger function returns this for chaining purpose.

    An event is not like a function call. Keep in mind that no code could be listening to it, or that multiple listeners could be bound to that event, so a return value would make no sense.

    It's good to use events to avoid strong coupling. If the view triggering the event needs some data back, there are some patterns you can use.

    Pass a callback with the event

    onHealthCallback: function(health) {
        /* use health here */
    },
    
    saveRooms: function(dayId, solutionId, shiftId, day) {
        /* ... */
        this.trigger('getHealth', dayId, this.onHealthCallback.bind(this));
        /* ... */
    },
    

    Using Function's bind method, this will be available in onHealthCallback.

    Then, the listener can just call the callback passing the arguments you're expecting.

    this.listenTo(OverviewView, 'getHealth', function(dayId, callback) {
        callback(LoadSolutionView.getHealth(dayId));
    });
    

    Pass the view

    setHealth: function(health) {
        this.health = health;
        this.reactToHealhChange();
    },
    
    saveRooms: function(dayId, solutionId, shiftId, day) {
        /* ... */
        this.trigger('getHealth', dayId, this);
        /* ... */
    },
    

    bind is unnecessary since we're passing the whole instance.

    The listener has now access to the complete view, more flexible but more exposed.

    this.listenTo(OverviewView, 'getHealth', function(dayId, view) {
        view.setHealth(LoadSolutionView.getHealth(dayId));
    });