UNPKG

backbone.projections

Version:
151 lines (140 loc) 9.09 kB
<!doctype 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) -&gt; m.get('score'))</pre> </div> <p>There&#8217;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) -&gt; - 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 &#8220;liked&#8221; 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) -&gt; 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 &#8220;today&#8217;s&#8221; 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 = {}) -&gt; options.filter = (model) -&gt; 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&#8217;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&#8217;s a quick&#8217;n&#8217;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&#8217;s implement this in a more efficient way:</p> <div class="highlight-python"><pre>class EfficientDifference extends Filtered constructor: (underlying, subtrahend, options = {}) -&gt; options.filter = (model) -&gt; not subtrahend.contains(model) super(underlying, options) this.listenTo subtrahend, add: (model) =&gt; this.remove(model) if this.contains(model) remove: (model) =&gt; 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) -&gt; post.get('date').isToday()) topTodaysPosts = new Capped(todaysPosts, cap: 5 comparator: (post) -&gt; - post.get('likes'))</pre> </div> <p>will result in a <tt class="docutils literal"><span class="pre">topTodaysPosts</span></tt> projection which only contains &#8220;top 5 most liked posts from today&#8221;.</p> </div> </div> </div>