Giter Club home page Giter Club logo

backbone.virtualcollection's Introduction

Backbone VirtualCollection

Built at Teambox

Build Status

Backbone VirtualCollection allows you display a subset of a Backbone collection in a Backbone view that updates in real time. It works great with Marionette CollectionViews.

If you're thinking "why don't you just place the models you're interested in a new collection?" the answer is that the new collection won't update itself when new models are added to the original collection, so you're creating data inconsitency. That's why we need a VirtualCollection.

Installation

a) with npm npm install backbone-virtual-collection

b) or manually add backbone.virtual-collection.js directly to your web app.

Usage

For example, let's say you have a task collection, and want to show a list of tasks that belong to a specific user.

We can instantiate a virtual collection that only contains tasks that belong to Rupert (who has user_id 13). The constructor takes two parameters, the first is the parent collection, the second is a options object. The filter option specifies a function that takes the model as argument. You can also just specify a hash of attributes to match.

var virtual_collection = new VirtualCollection(tasks_collection, {
  filter: function (task) {
    return task.get('user_id') == 13;
  }
});
// or using a hash of attributes to match
virtual_collection = new VirtualCollection(tasks_collection, {
  filter: {
    user_id: 13
  }
});

var view = new TaskListView({
  collection: virtual_collection
});

The Marionette collection view will only display the tasks that belong to Rupert, and it will update automatically. In other words, when a task is created that belongs to Rupert it will appear, but not if it belongs to Bob.

Sorting

Be default, the virtual collection will have the same sorting order as the parent collection. However, a comparator can be specified to change this. The comparator behaves like a Backbone comparator. In other words, you can specify a function or the name of an attribute to sort by.

var virtual_collection = new VirtualCollection(tasks_collection, {
  filter: { user_id: 13 },
  comparator: 'name'
});
// tasks in the virtual_collection will be sorted by name

You can also change the sorting order on the fly.

virtual_collection.comparator = 'created_at';
virtual_collection.sort(); // triggers sort event
// virtual_collection is now sorted by date, but the parent collection has not changed

Unbinding

The virtual collection will keep listening to its parent collection until you call stopListening.

You can pass a destroy_with option when creating the virtual collection being that an event emitter. The virtual collection will stop listening to events when the destroy_with event emitter emits a destroy event.

var virtual_collection = new Backbone.VirtualCollection(collection, {
  filter: {foo: 'bar'},
  destroy_with: view
});

Note: Prior to Marionette 2.*, "destroy" was called "close". For compatibility with older versions of Marionette, the old option close_with is still available, handling the close event.

Update filter

It's very common that you'd want to update the filter being used and have the collection view update itself. updateFilter takes the same parameters as the original filter option (a hash, or a function) and regenerates the virtual collection without losing your view bindings.

virtual_collection.updateFilter({
  the_new: 'properties'
, are: 'lovely'
});

// or

virtual_collection.updateFilter(function (model) {
  return model.foo() === 'bar';
});

Philosophy

No data duplication

VirtualCollection does not store, or duplicate any data. We've used other solutions in the past, and duplicating data is just plain bad news.

It's Fast

VirtualCollection maintains an internal index of models that pass the filter. That way, using the accessors and iterators (map, each, etc) is fast. It doesn't have to go through the whole parent collection and re-evaluate all the filters.

Happy hacking!

ఠ ͟ಠ Pull requests are welcome, naturally

backbone.virtualcollection's People

Contributors

alex-pex avatar craigmichaelmartin avatar denishomich avatar disruptek avatar dremora avatar enov avatar fcsonline avatar gregorybarale avatar jackca avatar jackellis avatar jacobbuck avatar jimbugwadia avatar justinwinslow avatar jvanaert avatar maffoobristol avatar marcelklehr avatar master-contributor avatar masylum avatar maxholman avatar megawac avatar mllocs avatar morantron avatar omer avatar p3drosola avatar pwalker avatar realadamsinger avatar reubenrybnik avatar robonaut avatar spacek33z avatar wridder avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

backbone.virtualcollection's Issues

Tagged releases

It would be much appreciated if you could tag your releases. Thanks!

Option for creating deaf collections

Sometimes it's very convenient to create deaf virtual collections — one that does not listenToparents events. The reason would be a perfomance tricks.

How about an option something like listenTo: false or trackEvents: false?

Adding items to a sorted virtual collection does not trigger sort event

When adding new items to a Backbone collection with a comparator, Backbone triggers the sort event in addition to the add event. However, VirtualCollection does not fire the sort event when items are virtually added to a sorted virtual collection by adding models to the base collection or by updating a model's attributes to match a filter when it didn't before.

I ran into this issue when using VirtualCollection in conjunction with the collection binder provided by https://github.com/theironcook/Backbone.ModelBinder with option autoSort set to true. Because the sort event is not fired in this case, the collection binder does not reorder view elements automatically on virtual add like it does when using a Backbone collection.

Repro:

var collectionExample = function() {
    // set up a collection that has a comparator and initially contains at least one item
    var initialModels = [
        new Backbone.Model({
            Name: 'Last'
        })
    ];

    var collection = new Backbone.Collection(initialModels, { comparator: 'Name' });

    collection.on('add', function() {
        console.log('Add triggered for collection.');
    });

    collection.on('sort', function() {
        console.log('Sort triggered for collection.');
    });

    // add a model - Backbone triggers both add and sort
    var model = new Backbone.Model({ Name: 'First' });
    collection.add(model);
};

var virtualCollectionExample = function() {
    // set up a collection that contains more than one item
    var filteredModel = new Backbone.Model({ Name: 'First', Filtered: true });

    var initialModels = [
        new Backbone.Model({
            Name: 'Last',
            Filtered: false
        }),
        filteredModel
    ];

    var collection = new Backbone.Collection(initialModels);

    // set up a virtual collection that has a different comparator than the base collection and filters at least one of the items out
    var virtualCollection = new VirtualCollection(collection, {
        filter: function(model) { return !model.get('Filtered'); },
        comparator: 'Name'
    });

    virtualCollection.on('add', function() {
        console.log('Add triggered for virtual collection.');
    });

    virtualCollection.on('sort', function() {
        console.log('Sort triggered for virtual collection.');
    });

    // add a new model to the base collection - VirtualCollection triggers add but does not trigger sort
    collection.add(new Backbone.Model({
        Name: 'In Between',
        Filtered: false
    }));

    // cause a model to be "added" to the virtual collection by updating it to match the filter - VirtualCollection triggers add but does not trigger sort
    filteredModel.set('Filtered', false);
};

collectionExample();
virtualCollectionExample();

IE8 fix

Hello, I had problems on IE8, here are the changes I did to make it work

  • in _rebuildIndex: check that this.models[idx].off is a function before calling it
  • in buildFilter: replace Object.keys by _.keys

Models added twice to a virtual collection

I might have found a bug in the following scenario:
When a new model is created and added to the superset, the subset collection will also add it if it passes the filter.
After the model is persisted on the server it receives a new id value. (In my setup from a negative integer to a positive integer).
This will trigger the _onChange handler in VirtualCollection, which is supposed to check if the affected model is already in the subset. If not, and the model passes the filter, it will be added.
In this scenario the line var already_here = this.get(model); does not find the model, therefore the model is added again to the subset.
I have managed to bypass this behavior by prototyping the get method inside VirtualCollection to read:

get: function(obj) {
    if (obj == null) return void 0;
    return this._byId[obj.cid ? obj.cid : obj.id || obj];
},

It seems to work now that the model is not added again, but I'm unsure if this is a valid solution, if it might break other things or have a negative impact on performance.
Can anyone verify that this is a bug in VirtualCollection or perhaps intended behavior or a missing feature?

component.json

Hey there,

I'd love to be able to install this via component.
What are your thoughts on this? I could wrap up a pull request adding a component.json.

Properly override clone

Currently VirtualCollection does not override Backbone.Collection.clone. This breaks clients using that function since the default implementation passes this.models to this.constructor instead of this.collection. This causes an undefined function error in _rebuildIndex since array does not have each.

I have been working on an implementation, but am unsure how to preserve the filter (The backbone collection spec just says that the resulting collection will have the same models, but I think for VirtualCollection the behaviour should be the same too). Initially I made a copy of the options hash and stored it on this. However this backbone issue jashkenas/backbone#3013 made me rethink that solution. So now I just try to pass the bare essentials (the collection, the comparator and the filter) to get correct behaviour for a vanilla virtual collection, but I can't access the filter passed to the constructor anymore. Should I preserve the filter as a property and then pass it on in the options? Or should I set accepts to this.accepts and then call _rebuildIndex ? Or is there another even better option?

Add descriptions to tags

I understand this is extra work and not something anyone really likes doing, but it would be really helpful to see what's changed in each release if there was a description to go with each tag.

One can always look over the commits but it's much nicer to see a neat summary of changes.

efficiently keeping VirtualCollection sorted according to parent collection order

This is an RFC on a problem I have in keeping a VirtualCollection sorted according to the parent collection's order.

My application is designed with large Collections which can then have several layers of VirtualCollections above them. I wish all Collections to share the same sort order. I implemented comparators only on the "root" parent Collections. My comparators and filters can be relatively expensive to evaluate, so my goal is to optimize their use. Additionally, I periodically sort() the parent Collections because the sort order of models changes according to time and other dynamic factors.

Here are the changes that I'd like feedback on before I implement something that might not be acceptable for general inclusion:

  1. When the VirtualCollection lacks a comparator, adding an item causes an exhaustive search through the VirtualCollection's index to discover the correct insertion index for the sorted model. We should be able to use a binary search here at least, perhaps leveraging some Underscore methods to make it even faster.
  2. A method to sort the VirtualCollection's index according to the order of models in the parent Collection would make it trivial to monitor the parent's sort event and re-sort the VirtualCollection as a result.
  3. VirtualCollection could emit move events that would allow for much more efficient order changes. This breaks with Backbone's Collection interface, of course, but it seems pretty handy for VirtualCollection users. VirtualCollection could listen for and emit move events by default and maybe provide an adapter so that Backbone's Collection could mixin the event emissions.

Please share any thoughts on these ideas, or others you may have for improving performance.

Virtual collection of Virtual collection and using updateFilter

When I define a Virtual collection (col_child) which is based on another virtual collection (col_parent) and the parent collection (col_parent) has a filter which is updated using updateFilter this won't update to the child collections. That is because a virtual collection doesn't listen to it's parent's 'filter' event.

A fix for this is making a virtual collection also listen to it's parent 'filter' event. I'll submit a pull request using a method that works fine for me.

Looking forward to your thoughts on this.

Not compatible with 0.9.2

The current version (0.5) is not compatible with Backbone 0.9.2. This is the failing test output:


> [email protected] test /Users/pcomans/Code/Backbone.VirtualCollection
> mocha -R spec -C



  Backbone.VirtualCollection
    #constructor

      1) should bind 4 listeners to its collection

      2) should build an index on instantiation

      3) should accept a close_with option and bind to the `close` event (Marionette 1.*)

      4) should accept a destroy_with option and bind destroy event (Marionette 2.*)
    #model

      5) should inherit the model type of the parent collection
    #each

      6) should iterate over the virtual collection in order
    #indexOf

      7) should return the index of a model as ordered in the virtual collection
    #where

      8) finds all the models matching the given attributes
    #findWhere

      9) finds the first model matching the given attributes
    #pluck

      10) returns an array of ids

      11) returns an array of attribute values
    #_addIndex

      12) should use comparators to correctly order the model in the virtual collection
    #comparator

      13) should sort the virtual collection upon instantiation

      14) should not order the virtual collection when the comparator is falsey

      15) should accept a comparator()

      16) should accept a comparator() that compares two models

      17) should keep the virtual collection sorted when adding items

      18) should update the virtual collection when a `reset` event is triggered by the parent collection
    map

      19) should map the models in the virtual collection
    each

      20) should iterate over the models in the virtual collection
    get

      21) should return the model if it belongs in the virtual collection
    at

      22) should return the model at the specified index of the virtual collection
    toJSON

      23) should return a JSON representation of the models in the virtual collection
    add & remove

      24) should proxy up to the parent
    filter

      25) should receive the model and index as arguments
    buildFilter

      ✓ should build a single-attribute filter that matches a model 

      ✓ should build a single-attribute filter that rejects a model 

      ✓ should build a multiple-attribute filter that matches a model 

      ✓ should build a multiple-attribute filter that rejects a model 

      ✓ should build a filter that matches model attributes with null values 

      ✓ should build a filter that matches model attributes with undefined values 
    events

      26) should trigger a `reset` event when the parent collection is reset

      27) should trigger an `add` event when a matching model is added to the parent

      28) should not trigger an `add` event when an unmatching model is added to the parent

      29) should trigger a `remove` event when a matching model is removed from the parent

      30) should not trigger a `remove` event when an unmatching model is removed from the parent

      31) should trigger a `remove` event when a model no longer passes the filter

      32) should trigger an `add` event when a modified model now passes the filter

      33) should trigger a `change` event when a model in the virtual collection is changed

      34) should trigger a `filter` event when updateFilter() is called

      35) should trigger a `reset` event when updateFilter() is called
    accepts & get

      36) should not call accepts() when iterating over the virtual collection

      37) should not call get() when iterating over nested virtual collections
    sorting

      38) should ignore parent collection sort event if it has a comparator

      39) should should inherit new model order if it does not have a comparator

      40) should add new models at the correct position if it has a comparator that accepts one model

      41) should add new models at the correct position if it has a comparator that accepts two models


  6 passing (24ms)
  41 failing

  1) Backbone.VirtualCollection #constructor should bind 4 listeners to its collection:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:24:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  2) Backbone.VirtualCollection #constructor should build an index on instantiation:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:35:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  3) Backbone.VirtualCollection #constructor should accept a close_with option and bind to the `close` event (Marionette 1.*):
     TypeError: Cannot read property 'bind' of undefined
      at Function._.bind (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/underscore/underscore.js:612:27)
      at Backbone.Collection.extend.bindLifecycle (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:45:30)
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:28:36)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:46:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  4) Backbone.VirtualCollection #constructor should accept a destroy_with option and bind destroy event (Marionette 2.*):
     TypeError: Attempted to wrap on which is already wrapped
      at Object.wrapMethod (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/sinon/lib/sinon.js:77:25)
      at Object.spy (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/sinon/lib/sinon/spy.js:41:22)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:55:13)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)
  --------------
  Error: Stack Trace for original
      at Object.wrapMethod (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/sinon/lib/sinon.js:97:30)
      at Object.spy (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/sinon/lib/sinon/spy.js:41:22)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:45:13)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  5) Backbone.VirtualCollection #model should inherit the model type of the parent collection:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:73:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  6) Backbone.VirtualCollection #each should iterate over the virtual collection in order:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:87:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  7) Backbone.VirtualCollection #indexOf should return the index of a model as ordered in the virtual collection:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:105:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  8) Backbone.VirtualCollection #where finds all the models matching the given attributes:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:119:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  9) Backbone.VirtualCollection #findWhere finds the first model matching the given attributes:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:131:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  10) Backbone.VirtualCollection #pluck returns an array of ids:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:143:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  11) Backbone.VirtualCollection #pluck returns an array of attribute values:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:153:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  12) Backbone.VirtualCollection #_addIndex should use comparators to correctly order the model in the virtual collection:

  TypeError
      at Function._.bind (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/underscore/underscore.js:613:36)
      at _.extend.sort (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:720:31)
      at _.extend.add (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:626:33)
      at _.extend.reset (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:745:12)
      at new Backbone.Collection (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:565:22)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:160:28)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  13) Backbone.VirtualCollection #comparator should sort the virtual collection upon instantiation:

  TypeError
      at Function._.bind (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/underscore/underscore.js:613:36)
      at _.extend.sort (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:720:31)
      at _.extend.add (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:626:33)
      at _.extend.reset (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:745:12)
      at new Backbone.Collection (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:565:22)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:178:28)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  14) Backbone.VirtualCollection #comparator should not order the virtual collection when the comparator is falsey:

  TypeError
      at Function._.bind (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/underscore/underscore.js:613:36)
      at _.extend.sort (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:720:31)
      at _.extend.add (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:626:33)
      at _.extend.reset (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:745:12)
      at new Backbone.Collection (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:565:22)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:192:28)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  15) Backbone.VirtualCollection #comparator should accept a comparator():

  TypeError
      at Function._.bind (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/underscore/underscore.js:613:36)
      at _.extend.sort (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:720:31)
      at _.extend.add (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:626:33)
      at _.extend.reset (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:745:12)
      at new Backbone.Collection (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:565:22)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:207:28)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  16) Backbone.VirtualCollection #comparator should accept a comparator() that compares two models:

  TypeError
      at Function._.bind (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/underscore/underscore.js:613:36)
      at _.extend.sort (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:720:31)
      at _.extend.add (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:626:33)
      at _.extend.reset (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:745:12)
      at new Backbone.Collection (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:565:22)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:221:28)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  17) Backbone.VirtualCollection #comparator should keep the virtual collection sorted when adding items:

  TypeError
      at Function._.bind (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/underscore/underscore.js:613:36)
      at _.extend.sort (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:720:31)
      at _.extend.add (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:626:33)
      at _.extend.reset (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:745:12)
      at new Backbone.Collection (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:565:22)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:236:28)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  18) Backbone.VirtualCollection #comparator should update the virtual collection when a `reset` event is triggered by the parent collection:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:255:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  19) Backbone.VirtualCollection map should map the models in the virtual collection:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:272:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  20) Backbone.VirtualCollection each should iterate over the models in the virtual collection:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:286:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  21) Backbone.VirtualCollection get should return the model if it belongs in the virtual collection:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:302:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  22) Backbone.VirtualCollection at should return the model at the specified index of the virtual collection:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:316:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  23) Backbone.VirtualCollection toJSON should return a JSON representation of the models in the virtual collection:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:331:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  24) Backbone.VirtualCollection add & remove should proxy up to the parent:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:345:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  25) Backbone.VirtualCollection filter should receive the model and index as arguments:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:359:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  26) Backbone.VirtualCollection events should trigger a `reset` event when the parent collection is reset:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:402:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  27) Backbone.VirtualCollection events should trigger an `add` event when a matching model is added to the parent:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:414:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  28) Backbone.VirtualCollection events should not trigger an `add` event when an unmatching model is added to the parent:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:426:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  29) Backbone.VirtualCollection events should trigger a `remove` event when a matching model is removed from the parent:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:438:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  30) Backbone.VirtualCollection events should not trigger a `remove` event when an unmatching model is removed from the parent:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:450:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  31) Backbone.VirtualCollection events should trigger a `remove` event when a model no longer passes the filter:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:463:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  32) Backbone.VirtualCollection events should trigger an `add` event when a modified model now passes the filter:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:475:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  33) Backbone.VirtualCollection events should trigger a `change` event when a model in the virtual collection is changed:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:487:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  34) Backbone.VirtualCollection events should trigger a `filter` event when updateFilter() is called:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:500:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  35) Backbone.VirtualCollection events should trigger a `reset` event when updateFilter() is called:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:513:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  36) Backbone.VirtualCollection accepts & get should not call accepts() when iterating over the virtual collection:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:533:12)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  37) Backbone.VirtualCollection accepts & get should not call get() when iterating over nested virtual collections:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:549:20)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  38) Backbone.VirtualCollection sorting should ignore parent collection sort event if it has a comparator:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:583:16)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  39) Backbone.VirtualCollection sorting should should inherit new model order if it does not have a comparator:

  TypeError
      at Function._.bind (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/underscore/underscore.js:613:36)
      at _.extend.sort (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:720:31)
      at _.extend.add (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:626:33)
      at _.extend.reset (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:745:12)
      at Backbone.Collection (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:565:22)
      at new child (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/backbone/backbone.js:1392:34)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:596:24)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  40) Backbone.VirtualCollection sorting should add new models at the correct position if it has a comparator that accepts one model:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:618:16)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)

  41) Backbone.VirtualCollection sorting should add new models at the correct position if it has a comparator that accepts two models:
     TypeError: Object [object Object] has no method 'listenTo'
      at new Backbone.Collection.extend.constructor (/Users/pcomans/Code/Backbone.VirtualCollection/backbone.virtual-collection.js:34:12)
      at Context.<anonymous> (/Users/pcomans/Code/Backbone.VirtualCollection/test/spec.js:637:16)
      at callFn (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:223:21)
      at Test.Runnable.run (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runnable.js:216:7)
      at Runner.runTest (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:373:10)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:451:12
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:298:14)
      at /Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:308:7
      at next (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:246:23)
      at Object._onImmediate (/Users/pcomans/Code/Backbone.VirtualCollection/node_modules/mocha/lib/runner.js:275:5)
      at processImmediate [as _immediateCallback] (timers.js:336:15)



npm ERR! Test failed.  See above for more details.
npm ERR! not ok code 0

Listen to a specific attribute changes in a model in a virtual collection

The collection events of a collection 'C' in standard backbone of the form 'change:[attributeName]' are not triggered on the virtual collection for the same collection C. It would be nice to have the same events on the virtual collection as well. Or are there specific design reasons for this?

Backbone update event not being handled

as of backbone v1.2.0 — May 13, 2015, an "update" event is now triggered on a collection after models have been added/removed. Backbone.VirtualCollection currently does not support this

Updating a Marionette CollectionView when updating a VirtualCollection filter

So I have a CollectionView and I'm using your VirtualCollection as the collection. I would like to update the filter and then rerender the CollectionView but it doesn't work. Looking at the view, its collection seems to be a regular old Collection. How do I get the view to rerender when the VirtualCollection's filter changes?

Update NPM package

The current NPM package version is 0.4.5, from 9 months ago. It would be great to be able to use B.VC from NPM. Could you keep the NPM package updated please?

Change event triggered without options.index causes error

When triggering change event for model like this: model.trigger('change'), virtual collection will give following error:

Uncaught TypeError: Cannot read property 'index' of undefined backbone.virtualcollection.js:102

This is caused from _onChange function. It doesn't check if options actually has index. I'm not sure if you should provide the index when manually triggering events to models but I've seen quite a few times that change is triggered without options.

Caching, disabling and re-enabling subsets

I'm playing around with this plugin at the moment, it has been very useful so far. I have created a wrapper object that creates my subsets, comparators and filter functions dynamically and caches them.

In my system I'm creating many subsets over time. I'm trying to achieve the following:

  • create subset for current view
  • cache subset somewhere globally
  • when the view is closed, "disable" the subset (stopListening)
  • when view is opened again, get the subset from cache, "enable" and refresh it

Right now the plugin has no interface for that. I would have to manually call:

  • stopListening to disable
  • bind all events again manually and call _rebuildIndex to enable

.. or something along those lines.

Would such an implementation make sense, or would the increase in performance be marginal?

Event "change:attr" is not handled in some cases

Hi,

I think there is an issue about the trigger of events like "change:attr".

Case 1: expected behavior

  • You create a virtual collection from a collection populated with valid models by the filter function
  • You change an attribute of one of those models,
  • The event "change:attr" will be triggered by the virtual collection

Case 2: unexpected behavior

  • You add a model that is not valid in the collection
  • Make it valid, which will add it in the virtual collection
  • Change some attribute
  • The event "change:attr" will not be triggered by the virtual collection

My analysis:
If think the problem is when you add an element (with the "_onAdd" function), it will listen the "all" event to call the function "_onAllEvent" which make possible to trigger the "change:attr" event.
But if you add an invalid model and then make it valid, you will go through the "_onChange" function which will not listen to the "all" event.

Is it made on purpose? If not, when do you think you will be able to correct it?
Hope i'm clear enough.

NPM is not up to date

The last published version on npm is 0.4.15 - It could be good to allow everyone to get the 0.5 goodness!

Source Missing License Header

I noticed that the JavaScript file doesn't have a license header. This seems to be a common practice amongst JavaScript libraries.
Would it be possible to add the information to the file so users can easily adhere to the project's license?
Something like:
Licensed under the MIT License
Thanks.

Add underscore mixins

VirtualCollection has reduced functionality compared to Backbone.Collection, since it doesn't implement methods like pluck.

Is there a good reason to not implement underscore mixins? This is how Backbone does it:

// Underscore methods that we want to implement on the Collection.
// 90% of the core usefulness of Backbone Collections is actually implemented
// right here:
var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
  'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
  'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
  'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
  'tail', 'drop', 'last', 'without', 'indexOf', 'shuffle', 'lastIndexOf',
  'isEmpty', 'chain'];

// Mix in each Underscore method as a proxy to `Collection#models`.
_.each(methods, function(method) {
  Collection.prototype[method] = function() {
    var args = slice.call(arguments);
    args.unshift(this.models);
    return _[method].apply(_, args);
  };
});

Add close_with option

Pass a close_with option, being that an Event emitter.

So when the Event emitter emits the close event, the VC will stop listening Events. Since the VC is the responsible of listening the events, it should be the responsible of closing them (if wanted).

virtual_collection = new Backbone.VirtualCollection(tasks_collection, {
  filter: {user_id: 13}
, close_with: an_event_emitter
});

I could do the PR.

latest version in bower is 0.5.0

According to latest bower.json file from master branch the latest version is 0.4.15. But after running:

bower install backbone-virtual-collection --save

I got 0.5.0 version.

Should we fix it and make things more clear?

Garbage Collection

It seems that the VirtualCollection instances will not be garbage collected, since for each accepted model an event listener is registered:

_rebuildIndex: function () {
...
    this.collection.each(function (model, i) {
      if (this.accepts(model, i)) {
        model.on('all', this._onAllEvent, this);
...
}

The event listener is however not deregistered inside the bindLifecycle method. I guess model.off(...) should be called when a destroy event is emitted, e.g.:

bindLifecycle: function (view, method_name) {
  view.on(method_name, _.bind(function() {
    this.stopListening();
    _.invoke(this.models, 'off', 'all', this._onAllEvent, this);
  }, this));
}

Any thoughts?

Marionette

Hello again,

I'm new to backbone and just getting started with all this stuff.
So, I'm wondering if I can also use your VirtualCollections without Marionette.
And if not, what is Marionette good for (in general and in this use case)?
Could you enlighten me?

thanks in advance

Create a virtual collection from multiple collections

I'd like to be able to pass in multiple collections and filter them to create the virtual collection.

Use case:

I'm using VirtualCollection for a search feature. I am searching inside a directory.

As the user types, I will filter this directory's children collection to only display children which match whatever the user typed.

In addition to filtering, I also want to show results from an API response. This allows me to have a single collection which can easily be represented using a simple list view.

Problem with Sort when not overridden

Had an error in the console when attempting to sort the virtual collection. Looks like it didn't properly get the comparator from the original collection. I'm trying to return a filtered set of accounts with an association to the goal. Pretty standard stuff.

class Collections.AccountsCollection extends Backbone.Collection

  comparator: (m) ->
    return -Date.parse(m.get('updatedAt'))

  belongToGoal: (id) ->
    new ViritualCollection(@, {filter: {goalId: id}})

and the code that caused the error. Dashboard.goal is the goal that the accounts are associated to.

Dashboard.accounts = new Collections.AccountsCollection(jsonResponse)
@accounts = Dashboard.accounts.belongToGoal(Dashboard.goal.get('id'))
@updatedAt = moment(@accounts.sort().pluck('updatedAt')[0]).fromNow()

my current work around is just passing in the defined comparator to the virtual collection on init. This makes the sort happen correctly.

belongToGoal: (id) ->
  new VirtualCollection(@, {filter:{goalId: id}, comparator: @comparator})

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.