documentcloud/backbone — pull request #1636 by anthonyshort (2012-09-10 02:05:08+00:00)
Title: Added 'include' allow for mixin functionality

One ability that Backbone lacks on it's objects is the ability to easily mixin functionality. 'Plugins' and 'extensions' require us to either extend their version of Backbone objects or we need to mix the functionality in using obscure methods.

These methods aren't necessarily bad, but they are often unclear and having a better interface for mixins on views, models and collections would make extending Backbone much easer.

I've added an `include` method that does just this. It mimics the functionality from Spine.js (which it borrowed from Ruby I'm assuming).

Example:

```js
var MyView = Backbone.View.extend();
MyView.include(CompositeView);
MyView.include(EditableView);
MyView.include(DraggableView);

var MyModel = Backbone.Model.extend();
MyModel.include(Validation);

```

It allows for a very nice syntax in coffeescript also:

```coffee
class MyView extends Backbone.View
@include CompositeView
@include EditableView
@include DraggableView
```

This allows you to mix functionality into the prototype of objects easily. Obviously this can be done with a simple _.extend. But this gives it a consistent interface that extensions can use to augment the functionality of the standard Backbone objects.

Firing the callback on the mixin allows for great separation of concerns. You can extend Backbone without needing to increase the size of the hierarchy.

```coffee
SelectableView =

included: ->
this.prototype.events['click'] = '_onSelectClick';
this.prototype.initialize = -> @selected = false
this.prototype.dispose = -> @unselect()

select: ->
unselect: ->
isSelected: -> @selected
```

```coffee
class TaskListItem extends Backbone.View
@include SelectableView

task = new TaskListItem
task.isSelected() # false
task.select()
```

This is generic enough that I think it could be of use for most, if not all, Backbone applications. I've needed this functionality on every project so far.

Test included. I'd like to see what others think of this approach.