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?
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"
I might recommend using Backbone.Cocktail 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 blog post.
you can use this gist https://gist.github.com/3652964
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"
}
});
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
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).
Success story sharing