2

I have a complex model served from my back end, which has a bunch of regular attributes, some nested models, and a couple of collections.

My page has two tables, one for invalid items, and one for valid items. The items in question are from one of the nested collections. Let's call it baseModel.documentCollection, implementing DocumentsCollection.

I don't want any filtration code in my Marionette.CompositeViews, so what I've done is the following (note, duplicated for the 'valid' case):

var invalidDocsCollection = new DocumentsCollection(
     baseModel.documentCollection.filter(function(item) {
            return !item.isValidItem();
     })
);

var invalidTableView = new BookIn.PendingBookInRequestItemsCollectionView({
    collection: app.collections.invalidDocsCollection
});

 layout.invalidDocsRegion.show(invalidTableView);

This is fine for actually populating two tables independently, from one base collection. But I'm not getting the whole event pipeline down to the base collection, obviously. This means when a document's validity is changed, there's no neat way of it shifting to the other collection, therefore the other view.

What I'm after is a nice way of having a base collection that I can have filter collections sit on top of. Any suggestions?

damienc88
  • 1,957
  • 19
  • 34

1 Answers1

1

I fleshed out my previous attempt and have come up with an extension to Backbone.Collection that does what I need.

collections.FilteredCollection = Backbone.Collection.extend({
   initialize: function(items, options) {
       if (_.isUndefined(options.baseCollection))
           throw "No base collection to watch";
       if (!_.isFunction(options.filterFunc)) {
           throw "No filter to apply";
       }
       _.extend(this, options);
       this.listenTo(this.baseCollection, 'all', this.reraise);
   },
   reraise: function (event) {
       this.reset(this.baseCollection.filter(this.filterFunc), { silent: true });
       var args = [].slice.call(arguments, 1);
       this.trigger(event, args);
   }
});

The one small issue I have with this is that I have to manually apply filterFunc to the baseCollection, then pass that in as the items parameter when instantiating a FilteredCollection, but that's something I can live with.

The below code is what I'm using to instantiate. Note that there's another almost-exact copy which is for the collection of ONLY VALID items, but any filters can be applied.

var allDocs = theModel.get('Documents');

var invalidOptions = {
    baseCollection: allDocs,
    filterFunc: function(item) {
        return !item.isValidItem();
    }
};

var invalidDocs = allDocs.filter(invalidOptions.filterFunc);
var invalidDocsCollection = new collections.FilteredCollection(
    invalidDocs, invalidOptions
);
damienc88
  • 1,957
  • 19
  • 34