pourover
Version:
A library for simple, fast filtering and sorting of large collections in the browser
157 lines (123 loc) • 8.43 kB
JavaScript
// #Advanced Views
// 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
// First, let's use our set up from the [basic example](/pourover/examples/examples_build/basic_pourover_ing.html)
var monsters = [{name: "sphinx", mythology: "greek", eyes: 2, sex: "f", hobbies: ["riddles","sitting","being a wonder"]},
{name: "hydra", mythology: "greek", eyes: 18, sex: "m", hobbies: ["coiling","terrorizing","growing"]},
{name: "huldra", mythology: "norse", eyes: 2, sex: "f", hobbies: ["luring","terrorizing"]},
{name: "cyclops", mythology: "greek", eyes: 1, sex: "m", hobbies: ["staring","terrorizing"]},
{name: "fenrir", mythology: "norse", eyes: 2, sex: "m", hobbies: ["growing","god-killing"]},
{name: "medusa", mythology: "greek", eyes: 2, sex: "f", hobbies: ["coiling","staring"]}];
var collection = new PourOver.Collection(monsters);
var mythology_filter = PourOver.makeExactFilter("mythology", ["greek","norse"]);
var gender_filter = PourOver.makeExactFilter("sex", ["m","f"]);
var hobbies_filter = PourOver.makeInclusionFilter("hobbies",["riddles",
"sitting",
"being a wonder",
"coiling",
"terrorizing",
"growing",
"luring",
"staring",
"god-killing"]);
collection.addFilters([mythology_filter, gender_filter, hobbies_filter]);
var view = new PourOver.View("default_view", collection);
// ### Sorting
// #### Creating a custom sort
// To create a custom sort, we generally extend the Sort object with a `fn`, the comparator function used to order items.
// We also specify which attribute the sort operates over -- what it sorts with respect to -- with the `attr` attribute.
// Then, we instantiate our new sort. This attr field has no special signifigance other than convention. You must still
// manually extract values in your sort function.
var RevNameSort = PourOver.Sort.extend({
fn: function(a,b){
var x = a.name, y = b.name;
if (y < x){
return -1;
} else if (y > x){
return 1;
} else {
return 0;
}
}
});
// We create a new sort and we associate it with attrs, so that when those attributes change -- if an item's name can change --
// then the sort will rebuild itself.
var rev_name_sort = new RevNameSort("rev_name", {associated_attrs: ["name"]});
// Like we do with filters, we add the sort to the collection. This indexes the sort of the current items. Additionally, `addSorts`
// binds collection changes to a re-sorting operation.
collection.addSorts([rev_name_sort]);
// Once we have added the sort we can call the `setSort` 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.
view.setSort("rev_name");
// Now, we when call `view.getCurrentItems`, the items will be sorted accordingly.
view.getCurrentItems();
// ### Sort Types
// PourOver ships with two default sorts, `explicitSort` and `reverseCidSort`
// `explicitSort` 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. `explicitSort`s are used for, among other things,
// user-defined orders or arbitrary orders.
// The `makeExplicitSort` constructor takes `(sort_name: String, collection: Collection, attribute_represented_in_order: String, order: [attribute])`
// 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 `explicitSort` on will be a GUID.
var my_slideshow_sort = PourOver.makeExplicitSort("my_slideshow_order",collection,"name",["hydra","huldra","medusa","cyclops","fenrir","sphinx"])
// `reverseCidSort` 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
var rev_cid_sort = PourOver.makeReverseCidSort("rev_sort",collection)
collection.addSorts([my_slideshow_sort,rev_cid_sort])
view.setSort("my_slideshow_order")
// ### Custom View types
// 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 `PourOver.View` object with a new selectionFn.
// *NOTE: The selectionFn must return a `MatchSet`, not a raw array of items. This `MatchSet` gets cached on the view for subsequent queries/renders.*
// 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.
var CustomView = PourOver.View.extend({
selectionFn: function(){
var mythology_query = collection.filters.mythology.current_query,
sex_query = collection.filters.sex.current_query;
return mythology_query.not(sex_query);
},
render: function(){
current_items = this.getCurrentItems();
console.log(current_items);
}
})
var custom_view = new CustomView("custom_view",collection);
custom_view.on("update",custom_view.render);
// Now, `custom_view.getCurrentItems()` 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
// ### Pattern: User favorites
// 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?
// Absolutely.
// First, lets make a new collection so as to not interfere with the previous part of the example
var collection_two = new PourOver.Collection(monsters);
// Now, we will need three new objects:
// - a filter that represents the objects a user has selected, a favorites filter
// - a grid view that intersects the hobby, mythology, and sex queries but ignores the favorites filter
// - a favorites view that ignores every filter but the favorites filter
// We use `manualFilter` to create the favorites filter. A `manualFilter` is exactly what it sounds like: a filter that you manually
// control, adding and removing items to specify which items it selects.
var favorites_filter = PourOver.makeManualFilter("favorites");
collection_two.addFilters([mythology_filter, gender_filter, hobbies_filter, favorites_filter]);
// 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)
var user_selection_cids = [1,3];
collection_two.filters.favorites.addItems(user_selection_cids);
// Now, we make a grid view that ignores the favorites filter
var GridView = PourOver.View.extend({
selectionFn: function(){
var mythology_query = collection_two.filters.mythology.current_query,
sex_query = collection_two.filters.sex.current_query,
hobbies_query = collection_two.filters.hobbies.current_query;
return mythology_query.and(sex_query).and(hobbies_query);
}
});
var grid_view = new GridView("grid_view",collection_two)
// Finally, we make a favorite view that only considers the favorites filter
var FavView = PourOver.View.extend({
selectionFn: function(){
return collection_two.filters.favorites.current_query;
}
});
var fav_view = new FavView("fav_view",collection_two)
// Now, `grid_view.getCurrentItems()` will only be affected by queries on mythology, sex, or hobbies.
// `fav_view.getCurrentItems()` will only be affected by queries (`addItems` and `removeItems`) on the favorites filter