backbone.projections
Version:
Various projections for Backbone.Collection
151 lines (140 loc) • 9.09 kB
HTML
<meta http-equiv="Content-Type" content="text/html; charset=utf8" />
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<script src="_static/jquery.js"></script>
<script src="_static/jquery.lettering.js"></script>
<script>
$(function() {
var $headers = $('h1,h2,h3,h4,h5,h6');
$headers.lettering('words').children('span').lettering();
$headers.children('span').children('span:contains("¶")').addClass('x');
});
</script>
<div class="main">
<div class="section" id="backbone-projections">
<h1>Backbone.Projections<a class="headerlink" href="#backbone-projections" title="Permalink to this headline">¶</a></h1>
<p>A set of projections for Backbone.Collection</p>
<p>Projection is a read-only collection which contains some subset of an other
underlying collection and stays in sync with it. That means that projection will
respond correspondingly to <tt class="docutils literal"><span class="pre">add</span></tt>, <tt class="docutils literal"><span class="pre">remove</span></tt> and other events from an underlying
collection.</p>
<p>Currently there are four available projections — <tt class="docutils literal"><span class="pre">Sorted</span></tt>, <tt class="docutils literal"><span class="pre">Reversed</span></tt>, <tt class="docutils literal"><span class="pre">Capped</span></tt>
and <tt class="docutils literal"><span class="pre">Filtered</span></tt>.</p>
<div class="contents local topic" id="the-documentation-is-organized-in-the-following-sections">
<p class="topic-title first">The documentation is organized in the following sections</p>
<ul class="simple">
<li><a class="reference internal" href="#usage-with-browserify" id="id1">Usage with Browserify</a></li>
<li><a class="reference internal" href="#sorted-and-reversed" id="id2">Sorted and Reversed</a></li>
<li><a class="reference internal" href="#capped" id="id3">Capped</a></li>
<li><a class="reference internal" href="#filtered" id="id4">Filtered</a></li>
<li><a class="reference internal" href="#complex-predicates-with-filtered-projections" id="id5">Complex predicates with Filtered projections</a></li>
<li><a class="reference internal" href="#composing-projections" id="id6">Composing projections</a></li>
</ul>
</div>
<p>See also <a class="reference external" href="http://andreypopp.com/posts/2013-05-15-projections-for-backbone-collections.html">blog post</a> for examples and demos.</p>
<div class="section" id="usage-with-browserify">
<h2><a class="toc-backref" href="#id1">Usage with Browserify</a><a class="headerlink" href="#usage-with-browserify" title="Permalink to this headline">¶</a></h2>
<p>Install with npm, use with <a class="reference external" href="http://browserify.org">Browserify</a>:</p>
<div class="highlight-python"><pre>% npm install backbone.projections</pre>
</div>
<p>and in your code:</p>
<div class="highlight-python"><pre>BackboneProjections = require 'backbone.projections'</pre>
</div>
</div>
<div class="section" id="sorted-and-reversed">
<h2><a class="toc-backref" href="#id2">Sorted and Reversed</a><a class="headerlink" href="#sorted-and-reversed" title="Permalink to this headline">¶</a></h2>
<p><tt class="docutils literal"><span class="pre">Sorted</span></tt> provides a projection which maintains its own order. You are
required to provide a comparator:</p>
<div class="highlight-python"><pre>{Sorted} = require 'backbone.projections'
collection = new Collection([...])
sorted = new Sorted(collection, comparator: (m) -> m.get('score'))</pre>
</div>
<p>There’s also a special case <tt class="docutils literal"><span class="pre">Reversed</span></tt> which maintains order reversed
to an underlying collection order:</p>
<div class="highlight-python"><pre>{Reversed} = require 'backbone.projections'
collection = new Collection([...])
sorted = new Reversed(collection)</pre>
</div>
</div>
<div class="section" id="capped">
<h2><a class="toc-backref" href="#id3">Capped</a><a class="headerlink" href="#capped" title="Permalink to this headline">¶</a></h2>
<p><tt class="docutils literal"><span class="pre">Capped</span></tt> provides a projection of a limited number of elements from an
underlying collection:</p>
<div class="highlight-python"><pre>{Capped} = require 'backbone.projections'
collection = new Collection([...])
capped = new Capped(collection, cap: 5)</pre>
</div>
<p>Using <tt class="docutils literal"><span class="pre">cap</span></tt> parameter you can restrict the number of models capped collection
will contain. By default this projection tries to maintain the order of models
induced by underlying collection but you can also pass custom comparator, for
example:</p>
<div class="highlight-python"><pre>topPosts = new Capped(posts,
cap: 10
comparator: (post) -> - post.get('likes'))</pre>
</div>
<p>will create a <tt class="docutils literal"><span class="pre">topPosts</span></tt> collection which will contain first 10 most “liked”
posts from underlying <tt class="docutils literal"><span class="pre">posts</span></tt> collection.</p>
</div>
<div class="section" id="filtered">
<h2><a class="toc-backref" href="#id4">Filtered</a><a class="headerlink" href="#filtered" title="Permalink to this headline">¶</a></h2>
<p><tt class="docutils literal"><span class="pre">Filtered</span></tt> provides a projection which contains a subset of models
from an underlying collection which match some predicate:</p>
<div class="highlight-python"><pre>{Filtered} = require 'backbone.projections'
todaysPosts = new Filtered(posts,
filter: (post) -> post.get('date').isToday())</pre>
</div>
<p>The example above will create a <tt class="docutils literal"><span class="pre">todaysPosts</span></tt> projection which only contains
“today’s” posts from the underlying <tt class="docutils literal"><span class="pre">posts</span></tt> collection.</p>
<p>By default this projection tries to maintain the order of models
induced by underlying collection but you can also pass custom comparator.</p>
</div>
<div class="section" id="complex-predicates-with-filtered-projections">
<h2><a class="toc-backref" href="#id5">Complex predicates with Filtered projections</a><a class="headerlink" href="#complex-predicates-with-filtered-projections" title="Permalink to this headline">¶</a></h2>
<p><tt class="docutils literal"><span class="pre">Filtered</span></tt> can be a base for complex projection which includes more
than a single collection, as an example we will implement a difference between
two collections:</p>
<div class="highlight-python"><pre>class Difference extends Filtered
constructor: (underlying, subtrahend, options = {}) ->
options.filter = (model) -> not subtrahend.contains(model)
super(underlying, options)
this.listenTo subtrahend, 'add remove reset', this.update.bind(this)
a = new Model()
b = new Model()
c = new Model()
d = new Model()
underlying = new Collection [a, b, c]
subtrahend = new Collection [b, c, d]
diff = new Difference(underlying, subtrahend)</pre>
</div>
<p>This way <tt class="docutils literal"><span class="pre">diff</span></tt> will contain only models from <tt class="docutils literal"><span class="pre">underlying</span></tt> which are not members
of <tt class="docutils literal"><span class="pre">subtrahend</span></tt> collection and what’s more important <tt class="docutils literal"><span class="pre">diff</span></tt> will track changes
in <tt class="docutils literal"><span class="pre">subtrahend</span></tt> and update itself accordingly.</p>
<p>But that’s a quick’n’dirty way of implementing this because on each change to
<tt class="docutils literal"><span class="pre">subtrahend</span></tt> the difference will reexamine entire <tt class="docutils literal"><span class="pre">underlying</span></tt> collection. Let’s
implement this in a more efficient way:</p>
<div class="highlight-python"><pre>class EfficientDifference extends Filtered
constructor: (underlying, subtrahend, options = {}) ->
options.filter = (model) -> not subtrahend.contains(model)
super(underlying, options)
this.listenTo subtrahend,
add: (model) =>
this.remove(model) if this.contains(model)
remove: (model) =>
this.add(model) if this.underlying.contains(model)
reset: this.update.bind(this)</pre>
</div>
</div>
<div class="section" id="composing-projections">
<h2><a class="toc-backref" href="#id6">Composing projections</a><a class="headerlink" href="#composing-projections" title="Permalink to this headline">¶</a></h2>
<p>You can compose different projection which each other, for example:</p>
<div class="highlight-python"><pre>todaysPosts = new Filtered(posts,
filter: (post) -> post.get('date').isToday())
topTodaysPosts = new Capped(todaysPosts,
cap: 5
comparator: (post) -> - post.get('likes'))</pre>
</div>
<p>will result in a <tt class="docutils literal"><span class="pre">topTodaysPosts</span></tt> projection which only contains “top 5 most
liked posts from today”.</p>
</div>
</div>
</div>