Tips:
• Apply a filter (color or location), then change that filter but hold cmd/ctrl when you do.
• Click on the "count" button to reveal "bulk actions"
• Try searching for name or email.
• Then try typing "loc:" proceeded by a location name. Ex: "loc:oregon".
In any application dealing with a significant amount of data, displaying a list of data will be necessary. This could be for reporting, work progress, or data review. Whatever the use case, List Controller lessens the burden of generating these list.
List Controller improves DOM responsiveness by lazy loading the rows with infinite scrolling. The library also provides common list actions: sorting, filtering, and bulk actions. Filters are stored in local storage so that the application remembers the last selected filter set. In addition, multiple filters can be saved as a "preset" for quickly using later.
This library has been 3+ years in the making here at Blackstone Audio. It is used everyday in dozens of areas inside our ERP application and is constantly being improved.
List Controller relies heavliy on Dropdown.js for the list actions (sort, filter, and bulk actions).
To use List Controller, you at least need these three things:
1) Collection
var Coll = SortableCollection.extend({})
2) List View (view for each row)
var ListView = Backbone.View.extend({ tagName: 'li', className: 'row', render: function(){ this.$el.html(this.model.get('label')) return this; } })
3) List Controller
var Controller = ListController.extend({ el: '#demo', listView: ListView, // tell infinite scroll to load more when reaching the end of this list scrollContext: '#demo .list', initialize: function(){ var fakeData = [], i=0; while(i++<60){ fakeData.push({id: i, label: 'Row '+i})} this.collection = new Coll(fakeData); } }) var listController = new Controller(); // later... render the controller listController.render();
Working Example
Assuming your collection has some data in it, the code above is all you need to render an infinite scrolling list. See demo-2.js
Before adding sorts, filters, and other options, it is best to specify the following options on your SortableCollection for things to work right.
key
This is the key used to save selected sorts and filters to local storage. You want this unique so as not to conflict with other ListControllers you may use other places.
defaultSort
How should the collection be sorted upon first loaded?
defaultDesc
optionalShould the sort start in descending order?
dbSort
optionalIs the sorting done clientside in the browser, or should the server do the sorting instead? If this is set to true
, the collection will be refetched when sort changes to allow the server to return the new sorted data.
var Coll = SortableCollection.extend({ key : 'my-list-controller-collection', defaultSort : 'id', defaultDesc : false, dbSort : false, })
sorts
To allow the user to sort the data, add a list of available sorts to the ListController
var Controller = ListController.extend({ sorts: [ {label: 'ID', val: 'id'}, {label: 'Label', val: 'label'}, {label: 'Custom Label', val: 'custom-label-sort'} ] })
By default, sorting uses the val
, for example "id", and looks for that val on the model: return model.get(val);
If you need a custom sorting function for a particular sort key, like custom-label-sort
, you can specify it in the SortableCollection
var Coll = SortableCollection.extend({ sorts: { 'custom-label-sort': function(model, key, isDesc){ return model.get('randNum') } } })
You'll notice sorting by label doesn't use "natural" sorting. You can achieve this by extending backbone collections with this gist.
filters
This is one of the most powerful features of ListController. It relies on Dropdown.js for rendering and controlling the selection of filters and thus, uses a similar structure.
Filters are saved on the SortableCollection and have filter settings saved there. At bare minimum, you need to specify all the filter keys.
var Coll = SortableCollection.extend({ filters: [ {key: 'filter-1'}, {key: 'filter-2'}, {key: 'filter-3'} ] })
If you wish for a filter to default to certain value, you can set that by using val
. Note: the value will only be used if the user has not selected another value for that filter.
If you want the filtering to happen on the server for a particular key, add db:true
.
var Coll = SortableCollection.extend({ filters: [{ key: 'key-string', val: 'preset value', db: true }] })
Filters are setup on the ListController using a hash of filter keys and their settings.
var Controller = ListController.extend({ filters: { 'filter-1': { /* settings*/ }, 'filter-2': { /* settings*/ }, 'filter-3': { /* settings*/ }, } })
label
optional: stringThe label for the filter will made from the key using _.humanize()
. For example, if the key is "filter-1", it will become "Filter 1". If you do not like this default naming convention, you can specify the label
to be something else.
prefix
optional: stringWhen a filter value is selected, the value's label will be displayed. Sometimes the value itself conflicts with other filter values. For example, maybe multiple filter keys have a "Many" filter value. It would be confusing the see multiple filters that say "Many" with no other context. Setting a prefix to something like "Filter 1: " will make the selected filter display as "Filter 1: Many".
values
hash / hashThis is the core of each filter. It's structure is the same as Dropdown.js. It accepts a hash or a function returning a hash.
values: [ {label: 'Clear Filter', val: ''}, 'divider', {label: 'Even ID', val: 'even'}, {label: 'Odd ID', val: 'odd'} ]
filterBy
optional: string preset / functionWhen a filter is selected, this is the method that is used to filter the data. There are presets created that can be reviewed under _defaultFilterMethods
in ListController.Settings.js
By default, the text
preset is used which attempts to compare the filter value on the model itself using a method or attribute of the same name:
model[filterVal].call() || model.get(filterVal)
Other presets include: number
, int
, array
, and model_id
.
Or you can use a function for your own logic:
function(model, filterVal, filterKey){}
multi
optional: boolIf set to true, multiple values can be selected by holding "cmd/ctrl". It's important to note that this means the filterVal
in filterBy
will be an array, not a string.
defaultValIndex
optional: intWhen the filters are "cleared", they go back to the default filter value which is the first (0) filter. This is generally fine most of the time, but if you wish for a different value other than the first to be the default, set the defaultValIndex
w
optional: intSets the width of the filter dropdown menu.
filterPresets
For now, see plugins/ListController.Presets.js
bulkActions
For now, see plugins/ListController.BulkSelect.js
MIT © Kevin Jantzer