Search code examples
jquerybackbone.jscoffeescriptmixinscocktail.js

For some reason my Backbone Cocktail.js mixin Event is being overwritten


My mixin

window.MyMixins = {}

MyMixins.GlobalViewMethods =

  events:
    'click #skipit' : 'skipit'

my view

Maestra.Views.Questions ||= {}

class Maestra.Views.Questions.Prereq extends Backbone.View
  @mixin MyMixins.GlobalViewMethods

  template: JST["backbone/templates/questions/prereq"]

  events:
    "click #stepone"                        : "open_stepone"
    "click #steptwo"                        : "open_steptwo"
    "click #stepthree"                      : "open_stepthree"
    "click #stepone, #steptwo, #stepthree"  : "add_complete"    
    "click #iamstupidready"                 : "check_question"  

When I run this, my mixin event does not work. However, if I remove all my events from my View, then the mixin event works. Otherwise, all the other events work, and the View's events always override the Mixin's events. Everything else klobbers fine ( render functions, constructor methods, etc. )

Is my syntax incorrect? Why is this not letting me mixin events?


Solution

  • The problem is that when @mixin runs:

    @mixin MyMixins.GlobalViewMethods
    

    There is no events in the class so no merging is done. Then, you hit the events:

    events:
      "click #stepone"                        : "open_stepone"
      #...
    

    and CoffeeScript will overwrite the events that @mixin added (remember that @mixin knows about merging, CoffeeScript doesn't). If we look at a simplified example, you should see what's going on; this CoffeeScript:

    class V extends Backbone.View
      @mixin MyMixins.GlobalViewMethods
      events:
        "click #in_v" : "in_v"      
    

    becomes this JavaScript (with a bunch of noisy boilerplate removed):

    V = (function(_super) {
      //...
      function V() {
        _ref = V.__super__.constructor.apply(this, arguments);
        return _ref;
      }
    
      V.mixin(MyMixins.GlobalViewMethods);
    
      V.prototype.events = {
        "click #in_v": "in_v"
      };
    
      return V;
    
    })(Backbone.View);
    

    Now you can see that @mixin (V.mixin) runs and merges some events into the non-existent V.prototype.events and then V.prototype.events is overwritten with the events from V.

    How do you solve an ordering problem? Well, you just adjust the order by putting your @mixin call at the bottom:

    class V extends Backbone.View
      events:
        "click #in_v" : "in_v"
      @mixin MyMixins.GlobalViewMethods
    

    Now @mixin will see the events in V and do some merging.

    Demo: http://jsfiddle.net/ambiguous/2f9hV/1/