1 | # ampersand-filtered-subcollection
|
2 |
|
3 | Lead Maintainer: [Michael Garvin](https://github.com/wraithgar)
|
4 |
|
5 | ## Purpose
|
6 |
|
7 | Filtered subset of a collection that emits events like a collection.
|
8 |
|
9 | Often for one part of an app you want a whole collection of models, but for another you want some sort of filtered subcollection. That's what this is for. It gives you a "pseudo collection" that behaves much like a full collection, but really is a subset.
|
10 |
|
11 |
|
12 | Part of the [Ampersand.js toolkit](http://ampersandjs.com) for building clientside applications.
|
13 |
|
14 |
|
15 | ## browser support
|
16 |
|
17 | [![browser support](https://ci.testling.com/ampersandjs/ampersand-filtered-subcollection.png)
|
18 | ](https://ci.testling.com/ampersandjs/ampersand-filtered-subcollection)
|
19 |
|
20 | ## install
|
21 |
|
22 | ```
|
23 | npm install ampersand-filtered-subcollection
|
24 | ```
|
25 |
|
26 | ## example
|
27 |
|
28 | ```javascript
|
29 | var WidgetCollection = require('./mycollection');
|
30 | var FilteredSubcollection = require('ampersand-filtered-subcollection');
|
31 |
|
32 |
|
33 | var widgets = new WidgetCollection();
|
34 |
|
35 | widgets.fetch();
|
36 |
|
37 | // this will create a collection-like object
|
38 | // that will only include models that match
|
39 | // the `where` filters.
|
40 | // It will be sorted by the comparator
|
41 | // independent of base collection order
|
42 | var favoriteWidgets = new FilteredSubcollection(widgets, {
|
43 | where: {
|
44 | awesome: true
|
45 | },
|
46 | comparator: function (model) {
|
47 | return model.rating;
|
48 | }
|
49 | });
|
50 | ```
|
51 |
|
52 | ## API reference
|
53 |
|
54 | ### new FilteredSubcollection(collection, [config])
|
55 |
|
56 | * `collection` {Collection} An instance of an ampersand-collection or Backbone.Collection that contains our full set of models.
|
57 | * `config` {Object} [optional] The config object that specifies whether or not a model in the base should be considered part of this subcollection.
|
58 | * `where` {Object} [optional] Object where each key is a property name of the model and the value is what you want that property to be in order for it to be included. Often used for boolean properties.
|
59 | * `filter` {Function} [optional] If you need more control than what you get from `where` you can use a filter function to determine if the model should be included. It will get called with a model and you simply return `true` or `false`.
|
60 | * `filters` {Array} [optional] If you for some reason want to pass in multiple filter functions you can do so. This can be useful in cases where you keep a reference to one that you may remove later without wanting to remove all your filtering rules. But, most of the time you would just do use `filter` and do all your logic in that one function.
|
61 | * `watched` {Array} [optional] This is an array of property names to watch for changes to in the base collection. This happens automatically if you use `where`. If your comparator and filters are all functions, then you will need to manually specify the relevant properties to watch so that re-filtering and re-sorting will occur when needed.
|
62 | * `comparator` {Function || String} [optional] If you want to determine sort order separate from the base collection provide this argument. If you pass a string it should be the name of the property that should be used to sort by, and it will be watched for changes automatically. If you pass a function, it will be passed the model and should return the value from the model that should be used to sort. If you pass a function that names two incoming arguments it will be used as a native `Array.prototype.sort`, where you get passed two models and return a `1`, `0`, `-1` to specify how they compare.
|
63 |
|
64 | ### .configure(config, [reset])
|
65 |
|
66 | Config can get used to update subcollection config post-init.
|
67 |
|
68 | * `config` {Object} Same config object as what you pass to init.
|
69 | * `reset` {Boolean} Default: `false`. Whether or not to remove all previous filter config options. If you specify `{where: {read: true}}` in the init and then do `.configure({where: {from: 'steve'}})` without passing `true` the collection will contain only read items from steve. The filters are combined by default. When `reset` is `true`, the `comparator` is also reset.
|
70 |
|
71 | ### .reset()
|
72 |
|
73 | Convenience method that calls `.configure({}, true)`
|
74 |
|
75 | ### .addFilter(filterFunction)
|
76 |
|
77 | * `filterFunction` {Function} A filter function as described above. Gets called with the model, you return `true` or `false`.
|
78 |
|
79 | ### .removeFilter(filterFunction)
|
80 |
|
81 | * `filterFunction` {Function} If you have a reference in your code to the filter function you added, you can remove it by calling `removeFilter`.
|
82 |
|
83 | ### .clearFilters()
|
84 |
|
85 | Removes filter functions and watches. After calling this, the subcollection should have the same models as your base collection.
|
86 |
|
87 | The only thing that does *not* get cleared is your `comparator` method or property if you have one.
|
88 |
|
89 | ### .swapFilters(newFilters, [oldFilters])
|
90 |
|
91 | * `newFilters` {Function} or array of filter functions to be applied to the collection.
|
92 | * `oldFilters` {Function} or array of filter functions to be removed from the collection. If `oldFilters` is undefined, then it is assumed to be the set of currently active filters.
|
93 |
|
94 | Replaces a set of existing filter functions with a set of new filters, and does not apply the results of the new filter combination until all have been added and removed.
|
95 |
|
96 | For example:
|
97 |
|
98 | ```javascript
|
99 | .swapFilters(newFilter, []) // Same as .addFilter(newFilter)
|
100 | .swapFilters([], oldFilter) // Same as .removeFilter(oldFilter)
|
101 | ```
|
102 |
|
103 |
|
104 | ### .at(index)
|
105 |
|
106 | * `index` {Number} returns model as specified index in the subcollection.
|
107 |
|
108 | ### .length
|
109 |
|
110 | The subcollection maintains a read-only length property that simply proxies to the array length of the models it contains.
|
111 |
|
112 | ### .models
|
113 |
|
114 | The array of filtered models
|
115 |
|
116 | ### FilteredSubcollection.extend(mixins...)
|
117 |
|
118 | FilteredSubcollection attaches `extend` to the constructor so if you want to add custom methods to your subcollection constructor, it's easy:
|
119 |
|
120 | ```javascript
|
121 | var FilteredSubcollection = require('ampersand-filtered-subcollection');
|
122 |
|
123 | // this exports a new constructor that includes
|
124 | // the methods you passed on the prototype while
|
125 | // maintaining the inheritance chain for instanceof
|
126 | // checks.
|
127 | module.exports = FilteredSubcollection.extend({
|
128 | myMethod: function () { ... },
|
129 | myOtherMethod: function () { ... }
|
130 | });
|
131 | ```
|
132 |
|
133 | This is done by using: [ampersand-class-extend](https://github.com/AmpersandJS/ampersand-class-extend)
|
134 |
|
135 | ## credits
|
136 |
|
137 | If you like this follow [@HenrikJoreteg](http://twitter.com/henrikjoreteg) on twitter.
|
138 |
|
139 | ## license
|
140 |
|
141 | MIT
|