Proper way of doing view mixins in Backbone

backbone.js

backbone.js Problem Overview


I extend base backbone views all the time and have a base view per section so that I can extend on multiple levels. My question is, what's the most effective way of doing view mixins: reusable view partials that can be mixed in to any view. For example:

var BaseProfile = Backbone.View.extend({ ...});
var UserProfile = BaseProfile.extend({ ...});
var VideoSupport = Backbone.View.extend({ ...});

What's the best way to mixin VideoSupport view (an event object and a few methods) with UserProfile view?

backbone.js Solutions


Solution 1 - backbone.js

The underscore.js library provides an extend method that does what you want. You can define functionality on any object, and then quite literally copy & paste all of the methods and attributes from that object to another.

Backbone's extend methods on Views, Models, and Routers are a wrapper around underscore's extend.

 var MyMixin = {
foo: "bar",
sayFoo: function(){alert(this.foo);}
}




var MyView = Backbone.View.extend({
// ...
});




_.extend(MyView.prototype, MyMixin);




myView = new MyView();
myView.sayFoo(); //=> "bar"

myView = new MyView(); myView.sayFoo(); //=> "bar"

Solution 2 - backbone.js

I might recommend using https://github.com/onsi/cocktail">Backbone.Cocktail</a> which provides a really succinct way of specifying mixins (that respect inheritance):

var Mixin = {
  initialize: function() {
    console.log("I'll be called as well as the class's constructor!");
  }
};

var View = Backbone.View.extend({
  mixins: [ MyMixin ]
});

I've detailed it in this http://www.salsify.com/blog/using-cocktail-to-create-mixins-for-backbone-models-that-respect-inheritance/1283">blog post.

Solution 3 - backbone.js

you can use this gist https://gist.github.com/3652964

Solution 4 - backbone.js

You can use Backbone.Mix library which used mixins embedded to the prototype chain

var Editable = {
    edit: function(){
        console.log('edit');
    }
};

var Article = Backbone.Model.mix(Editable).extend({
    initialize: function(){
        Backbone.Model.prototype.initialize.call(this);
        this.edit(); // logs "edit"
    }
});

Solution 5 - backbone.js

I needed the ability to override and invoke mixed in methods (ala super) closer to how ruby handles modules. And the simple extension method would clobber the mixin method if it existed in the class. Since I'm building it all in CoffeeScript I have access to the super object which lets me shim methods in. It will also automatically merge the events object so you can define event handlers in the mixin.

_.extend Backbone,
  mixin: (klass, mixin, merge) ->
    debugger unless mixin
    mixin = mixin.prototype || mixin
    merge ||= ["events"]

    sup = _.extend({},klass.__super__)

    for name,func of mixin      
      if base = sup[name] && _.isFunction(base)
        sup[name] = ->
          func.apply this, arguments
          base.apply this, arguments
      else
        sup[name] = func

    hp = {}.hasOwnProperty
    prototype = klass.prototype
    for name,func of mixin
      continue unless hp.call(mixin,name)
      continue if _(merge).contains name
      prototype[name] = func unless prototype[name]

    klass.__super__ = sup

    _(merge).each (name) ->
      if mixin[name]
        prototype[name] = _.extend({},mixin.events,prototype.events) 

    @

#Usage

class SimpleView extends Backbone.View
  events:
    "click .show" : "show"

  calculate: ->
    super + 5

  show: ->
    console.log @calculate()

class CalculatableViewMixin
  events:
    "click .calculate" : "show"
    
  calculate: ->
    15

Backbone.mixin SimpleView, CalculatableViewMixin

Solution 6 - backbone.js

Another option is the Backbone.Advice which provides power of AOP-styled mixins (you can inject custom behavior before, after or around calls of extended object methods).

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMauvis LedfordView Question on Stackoverflow
Solution 1 - backbone.jsDerick BaileyView Answer on Stackoverflow
Solution 2 - backbone.jsDan SView Answer on Stackoverflow
Solution 3 - backbone.jsuser873792View Answer on Stackoverflow
Solution 4 - backbone.jsjifeonView Answer on Stackoverflow
Solution 5 - backbone.jsPaul AlexanderView Answer on Stackoverflow
Solution 6 - backbone.jsipbdView Answer on Stackoverflow