Search code examples
javascripteventsbackbone.jscoffeescriptmixins

Use Backbone.View events method through a mixin


I'm using Backbone with Coffeescript in an app. Now the example that I'll use is made as trivial as possible. I have a header in my app that all the views share it. This header has a logout link with #logout index. Now what I'm trying to do is to put the events method and the method that the event will use it when it is triggered in a mixin object and extend the prototype of my Backbone View. Here is the code:

Mixin.Header =
  events: ->
    'click #logout': 'logout'

  logout: (e)->
    e.preventDefault()
    $.ajax(
      type: 'DELETE' 
      url: '/logout'
    ).then(
      ->
        document.location = ''
    )

class View extends Backbone.View
  initialize: (options)->
    _.extend(View.prototype, Mixin.Header)

I've been looking through the Backbone source code and I simply can't find the problem why this is not working. The events get delegated to the View through the delegateEvents() method and when the View is initialized the initialize method is being called first.


Solution

  • From the fine manual:

    events view.events or view.events()
    [...]
    Backbone will automatically attach the event listeners at instantiation time, right before invoking initialize.

    You're trying to add events in initialize but the events are bound before initialize is called.

    You could call delegateEvents yourself to rebind the events after you've updated the prototype:

    initialize: (options)->
      _.extend(View.prototype, Mixin.Header)
      @delegateEvents() # <----------
    

    but the structure would be a little weird because you'd be modifying the class inside an instance.

    I think you'd be better off modifying the class before you have any instances:

    class View extends Backbone.View
    _.extend(View.prototype, Mixin.Header)
    

    or you could use the CoffeeScript shortcut for prototype:

    class View extends Backbone.View
    _.extend(View::, Mixin.Header)
    # -----------^^
    

    or even:

    class View extends Backbone.View
      _.extend(@::, Mixin.Header)
    

    You will still run into problems if View has its own events as _.extend blindly overwrites properties rather than merging them. You'd need something smarter than _.extend to properly handle this and it would need to be able to figure out how to merge events functions and objects.