Wednesday, April 17, 2013

Patterns for Filtered Collections in Backbone

[caption id="attachment_842" align="alignleft" width="186">Master Collection and Filtered Subsets Master Collection and Filtered Subsets[/caption]

Most likely, you'll have a need to filter the data in a collection. Although there are built-in filtering functions in the Backbone Collection object, they don't affect the actual collection instance - just return an array of models. If you're trying to filter the collection to cause a view to render the filtered set, you'll need to put that array of models in another collection. It doesn't make sense to reset the collection you filtered, you might want to clear the filter and go back to the original data set.

I've been playing with both Backbone Query and Backbone Subset to figure out what approach might work best for building a consistent, repeatable pattern for this problem.

Subset provides an all-in-one solution with the ability to create a Subset object from a source collection, add filters, and bind a view to the filtered collection available in the Subset model. Since the filters are a collection as well, you can bind them into a view and build a UI around them so your list of filtered items will update automatically.

Query doesn't provide the same framework but does offer a more powerful filtering engine. Combining Subset and Query together would create a fairly powerful tool for extracting subsets of data from a primary source collection.

However, one size doesn't always fit all. I had a case where the filters I wanted to allow entered from the UI did not map nicely on to the collection in Subset and the filtering logic needed to be implemented as a custom function passed to the Backbone Collection filter() function.

I do think the overall pattern defined by the Subset solution makes sense:

  1. Start with a container model, add a source collection, filter collection, and results collection

  2. Instance the container model with the source collection

  3. Bind the container to a view that will manage the filter and list views

  4. Have the container view instance and render the filter/list views binding in the corresponding collections from the container model

  5. Add appropriate handler logic to listen to filter changes, apply transforms, and filter the source to reset the result collection

The actual querying/filtering implementation depends on you needs. The setup is basically the same. Now you maintain one instance of all your models but can render multiple views of those models based on the application requirements.