UNPKG

pourover

Version:

A library for simple, fast filtering and sorting of large collections in the browser

483 lines (331 loc) 22.2 kB
<!DOCTYPE html> <html> <head> <title>Advanced Views</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <ul id="jump_to"> <li> <a class="large" href="javascript:void(0);">Jump To &hellip;</a> <a class="small" href="javascript:void(0);">+</a> <div id="jump_wrapper"> <div id="jump_page"> <a class="source" href="advanced_filters.html"> advanced_filters.js </a> <a class="source" href="advanced_views.html"> advanced_views.js </a> <a class="source" href="basic_pourover_ing.html"> basic_pourover_ing.js </a> <a class="source" href="buffering.html"> buffering.js </a> </div> </li> </ul> <ul class="sections"> <li id="section-1"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-1">&#182;</a> </div> <h1 id="advanced-views">Advanced Views</h1> <p>This example will cover how to create and add sorts to collections, how to create custom view types with custom selectionFns, and some common PourOver view tricks</p> </div> </li> <li id="section-2"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-2">&#182;</a> </div> <p>First, let’s use our set up from the <a href="/pourover/examples/examples_build/basic_pourover_ing.html">basic example</a></p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> monsters = [{name: <span class="hljs-string">"sphinx"</span>, mythology: <span class="hljs-string">"greek"</span>, eyes: <span class="hljs-number">2</span>, sex: <span class="hljs-string">"f"</span>, hobbies: [<span class="hljs-string">"riddles"</span>,<span class="hljs-string">"sitting"</span>,<span class="hljs-string">"being a wonder"</span>]}, {name: <span class="hljs-string">"hydra"</span>, mythology: <span class="hljs-string">"greek"</span>, eyes: <span class="hljs-number">18</span>, sex: <span class="hljs-string">"m"</span>, hobbies: [<span class="hljs-string">"coiling"</span>,<span class="hljs-string">"terrorizing"</span>,<span class="hljs-string">"growing"</span>]}, {name: <span class="hljs-string">"huldra"</span>, mythology: <span class="hljs-string">"norse"</span>, eyes: <span class="hljs-number">2</span>, sex: <span class="hljs-string">"f"</span>, hobbies: [<span class="hljs-string">"luring"</span>,<span class="hljs-string">"terrorizing"</span>]}, {name: <span class="hljs-string">"cyclops"</span>, mythology: <span class="hljs-string">"greek"</span>, eyes: <span class="hljs-number">1</span>, sex: <span class="hljs-string">"m"</span>, hobbies: [<span class="hljs-string">"staring"</span>,<span class="hljs-string">"terrorizing"</span>]}, {name: <span class="hljs-string">"fenrir"</span>, mythology: <span class="hljs-string">"norse"</span>, eyes: <span class="hljs-number">2</span>, sex: <span class="hljs-string">"m"</span>, hobbies: [<span class="hljs-string">"growing"</span>,<span class="hljs-string">"god-killing"</span>]}, {name: <span class="hljs-string">"medusa"</span>, mythology: <span class="hljs-string">"greek"</span>, eyes: <span class="hljs-number">2</span>, sex: <span class="hljs-string">"f"</span>, hobbies: [<span class="hljs-string">"coiling"</span>,<span class="hljs-string">"staring"</span>]}]; <span class="hljs-keyword">var</span> collection = <span class="hljs-keyword">new</span> PourOver.Collection(monsters); <span class="hljs-keyword">var</span> mythology_filter = PourOver.makeExactFilter(<span class="hljs-string">"mythology"</span>, [<span class="hljs-string">"greek"</span>,<span class="hljs-string">"norse"</span>]); <span class="hljs-keyword">var</span> gender_filter = PourOver.makeExactFilter(<span class="hljs-string">"sex"</span>, [<span class="hljs-string">"m"</span>,<span class="hljs-string">"f"</span>]); <span class="hljs-keyword">var</span> hobbies_filter = PourOver.makeInclusionFilter(<span class="hljs-string">"hobbies"</span>,[<span class="hljs-string">"riddles"</span>, <span class="hljs-string">"sitting"</span>, <span class="hljs-string">"being a wonder"</span>, <span class="hljs-string">"coiling"</span>, <span class="hljs-string">"terrorizing"</span>, <span class="hljs-string">"growing"</span>, <span class="hljs-string">"luring"</span>, <span class="hljs-string">"staring"</span>, <span class="hljs-string">"god-killing"</span>]); collection.addFilters([mythology_filter, gender_filter, hobbies_filter]); <span class="hljs-keyword">var</span> view = <span class="hljs-keyword">new</span> PourOver.View(<span class="hljs-string">"default_view"</span>, collection);</pre></div></div> </li> <li id="section-3"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-3">&#182;</a> </div> <h3 id="sorting">Sorting</h3> </div> </li> <li id="section-4"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-4">&#182;</a> </div> <p>To create a sort, we generally extend the Sort object with a <code>fn</code>, the comparator function used to order items. We also specify which attribute the sort operates over — what it sorts with respect to — with the <code>attr</code> attribute. Then, we instantiate our new sort.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-keyword">var</span> RevNameSort = PourOver.Sort.extend({ attr: <span class="hljs-string">"name"</span>, fn: <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(a,b)</span>{</span> <span class="hljs-keyword">if</span> (b &lt; a){ <span class="hljs-keyword">return</span> -<span class="hljs-number">1</span>; } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (b &gt; a){ <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>; } <span class="hljs-keyword">else</span> { <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>; } } }); <span class="hljs-keyword">var</span> rev_name_sort = <span class="hljs-keyword">new</span> RevNameSort(<span class="hljs-string">"rev_name"</span>);</pre></div></div> </li> <li id="section-5"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-5">&#182;</a> </div> <p>Like we do with filters, we add the sort to the collection. This indexes the sort of the current items. Additionally, <code>addSorts</code> binds collection changes to a re-sorting operation.</p> </div> <div class="content"><div class='highlight'><pre> collection.addSorts([rev_name_sort]);</pre></div></div> </li> <li id="section-6"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-6">&#182;</a> </div> <p>Once we have added the sort we can call the <code>setSort</code> method of a view with the name of a sort that has been added to its collection. Even though sorts are added to collections, every view can set its sort independently.</p> </div> <div class="content"><div class='highlight'><pre> view.setSort(<span class="hljs-string">"rev_name"</span>);</pre></div></div> </li> <li id="section-7"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-7">&#182;</a> </div> <p>Now, we when call <code>view.getCurrentItems</code>, the items will be sorted accordingly.</p> </div> <div class="content"><div class='highlight'><pre>view.getCurrentItems();</pre></div></div> </li> <li id="section-8"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-8">&#182;</a> </div> <h3 id="sort-types">Sort Types</h3> </div> </li> <li id="section-9"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-9">&#182;</a> </div> <p>PourOver ships with two default sorts, <code>explicitSort</code> and <code>reverseCidSort</code></p> </div> </li> <li id="section-10"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-10">&#182;</a> </div> <p><code>explicitSort</code> models a sort in which an explicit order of cids is passed. This is how we model orders that have no functional reference to items’ attributes. <code>explicitSort</code>s are used for, among other things, user-defined orders or arbitrary orders. The <code>makeExplicitSort</code> constructor takes <code>(sort_name: String, collection: Collection, attribute_represented_in_order: String, order: [attribute])</code> Here, we define an explicit sort by passing in the order of the items, identified by their name attribute. Generally, the attribute that you store an <code>explicitSort</code> on will be a GUID.</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> my_slideshow_sort = PourOver.makeExplicitSort(<span class="hljs-string">"my_slideshow_order"</span>,collection,<span class="hljs-string">"name"</span>,[<span class="hljs-string">"hydra"</span>,<span class="hljs-string">"huldra"</span>,<span class="hljs-string">"medusa"</span>,<span class="hljs-string">"cyclops"</span>,<span class="hljs-string">"fenrir"</span>,<span class="hljs-string">"sphinx"</span>])</pre></div></div> </li> <li id="section-11"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-11">&#182;</a> </div> <p><code>reverseCidSort</code> is the reverse of the default sort. It sorts your items in the reverse of the order in which they were put into the collection</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">var</span> rev_cid_sort = PourOver.makeReverseCidSort(<span class="hljs-string">"rev_sort"</span>,collection) collection.addSorts([my_slideshow_sort,rev_cid_sort]) view.setSort(<span class="hljs-string">"my_slideshow_order"</span>)</pre></div></div> </li> <li id="section-12"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-12">&#182;</a> </div> <h3 id="custom-view-types">Custom View types</h3> </div> </li> <li id="section-13"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-13">&#182;</a> </div> <p>Changing our attention from sorts to the views they influence, how do we define custom views: views that combine their filters in a non-standard ways. Keeping with the Backbone-ese pattern of extension, we simply extend the <code>PourOver.View</code> object with a new selectionFn. <em>NOTE: The selectionFn must return a <code>MatchSet</code>, not a raw array of items. This <code>MatchSet</code> gets cached on the view for subsequent queries/renders.</em> Here, we create a custom view that takes the current query on “mythology” subtracts the current query on sex and ignores hobbies entirely. This could model a UI in which the user selects a mythology facet to view, a sex to hide and is unable to filter on hobby.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-keyword">var</span> CustomView = PourOver.View.extend({ selectionFn: <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span>{</span> <span class="hljs-keyword">var</span> mythology_query = collection.filters.mythology.current_query, sex_query = collection.filters.sex.current_query; <span class="hljs-keyword">return</span> mythology_query.not(sex_query); }, render: <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span>{</span> current_items = <span class="hljs-keyword">this</span>.getCurrentItems(); console.log(current_items); } }) <span class="hljs-keyword">var</span> custom_view = <span class="hljs-keyword">new</span> CustomView(<span class="hljs-string">"custom_view"</span>,collection); custom_view.on(<span class="hljs-string">"update"</span>,custom_view.render);</pre></div></div> </li> <li id="section-14"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-14">&#182;</a> </div> <p>Now, <code>custom_view.getCurrentItems()</code> will ignore the hobby query and return the result of the mythology query - that of sex. Whenever any query changes or the collection changes, the custom view will “render” this result</p> </div> </li> <li id="section-15"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-15">&#182;</a> </div> <h3 id="pattern-user-favorites">Pattern: User favorites</h3> </div> </li> <li id="section-16"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-16">&#182;</a> </div> <p>Say we wanted to have an app that renders a grid of items that users can filter. However, we also want to add a pop-up that will show the items that users have starred. Can we do this with a single collection and multiple views?</p> </div> </li> <li id="section-17"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-17">&#182;</a> </div> <p>Absolutely.</p> </div> </li> <li id="section-18"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-18">&#182;</a> </div> <p>First, lets make a new collection so as to not interfere with the previous part of the example</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-keyword">var</span> collection_two = <span class="hljs-keyword">new</span> PourOver.Collection(monsters);</pre></div></div> </li> <li id="section-19"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-19">&#182;</a> </div> <p>Now, we will need three new objects: </p> <ul> <li>a filter that represents the objects a user has selected, a favorites filter</li> <li>a grid view that intersects the hobby, mythology, and sex queries but ignores the favorites filter</li> <li>a favorites view that ignores every filter but the favorites filter</li> </ul> </div> </li> <li id="section-20"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-20">&#182;</a> </div> <p>We use <code>manualFilter</code> to create the favorites filter. A <code>manualFilter</code> is exactly what it sounds like: a filter that you manually control, adding and removing items to specify which items it selects.</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-keyword">var</span> favorites_filter = PourOver.makeManualFilter(<span class="hljs-string">"favorites"</span>); collection_two.addFilters([mythology_filter, gender_filter, hobbies_filter, favorites_filter]);</pre></div></div> </li> <li id="section-21"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-21">&#182;</a> </div> <p>When a user favorites an item, say the 2nd and 4th items in our collection, the hydra and the cyclops (this would happen in a callback)</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-keyword">var</span> user_selection_cids = [<span class="hljs-number">1</span>,<span class="hljs-number">3</span>]; collection_two.filters.favorites.addItems(user_selection_cids);</pre></div></div> </li> <li id="section-22"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-22">&#182;</a> </div> <p>Now, we make a grid view that ignores the favorites filter</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-keyword">var</span> GridView = PourOver.View.extend({ selectionFn: <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span>{</span> <span class="hljs-keyword">var</span> mythology_query = collection_two.filters.mythology.current_query, sex_query = collection_two.filters.sex.current_query, hobbies_query = collection_two.filters.hobbies.current_query; <span class="hljs-keyword">return</span> mythology_query.and(sex_query).and(hobbies_query); } }); <span class="hljs-keyword">var</span> grid_view = <span class="hljs-keyword">new</span> GridView(<span class="hljs-string">"grid_view"</span>,collection_two)</pre></div></div> </li> <li id="section-23"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-23">&#182;</a> </div> <p>Finally, we make a favorite view that only considers the favorites filter</p> </div> <div class="content"><div class='highlight'><pre><span class="hljs-keyword">var</span> FavView = PourOver.View.extend({ selectionFn: <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">()</span>{</span> <span class="hljs-keyword">return</span> collection_two.filters.favorites.current_query; } }); <span class="hljs-keyword">var</span> fav_view = <span class="hljs-keyword">new</span> FavView(<span class="hljs-string">"fav_view"</span>,collection_two)</pre></div></div> </li> <li id="section-24"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-24">&#182;</a> </div> <p>Now, <code>grid_view.getCurrentItems()</code> will only be affected by queries on mythology, sex, or hobbies. <code>fav_view.getCurrentItems()</code> will only be affected by queries (<code>addItems</code> and <code>removeItems</code>) on the favorites filter</p> </div> </li> </ul> </div> </body> </html>