#Tutorial: kb.CollectionObservable
Knockback.js provides an kb.CollectionObservable that watches Backbone.Collections when models are added, removed, and changed. In addition, kb.CollectionObservables can be used to sort models independently from the Backbone.Collection order, to bind HTML select elements, to render/edit model relationships, and to filter collections.
You can sort models using an attribute name or by providing a sorted_index function.
<div id='kbco_sorting' > <legend>Sort Attribute <select data-bind="options: sort_attributes, selectedOptions: sort_attribute"></select> </legend> <div data-bind="foreach: people"> <div class='row-fluid'> <div class='span5'> <span>First: </span> <input class='input-small' data-bind="value: first, valueUpdate: 'keyup'"/> </div> <div class='offset1 span5'> <span>Last: </span> <input class='input-small' data-bind="value: last, valueUpdate: 'keyup'"/> </div> </div> </div> </div>
people = new Backbone.Collection([{first: 'Jeremy', last: 'Sanderson'}, {first: 'Steven', last: 'Ashkenas'}]) sort_attribute = ko.observable('first') view_model = sort_attribute: sort_attribute sort_attributes: ko.observableArray(['first', 'last']) people: kb.collectionObservable(people, {sort_attribute: sort_attribute}) ko.applyBindings(view_model, $('#kbco_sorting')[0])
var ko = kb.ko; var people = new Backbone.Collection([{first: 'Jeremy', last: 'Sanderson'}, {first: 'Steven', last: 'Ashkenas'}]); var sort_attribute = ko.observable('first'); var view_model = { sort_attribute: sort_attribute, sort_attributes: ko.observableArray(['first', 'last']), people: kb.collectionObservable(people, {sort_attribute: sort_attribute}) }; ko.applyBindings(view_model, $('#kbco_sorting')[0]);
You can use kb.CollectionObservables to filter both ViewModels or Models (using the 'models_only' option) using the filters constructor option. Filters can be individual ids (observable or simple) or arrays of ids, functions, or arrays of functions.
<div id='kbco_filtering' > <legend>Filter Name <select data-bind="options: available_names, selectedOptions: filtered_names"></select> </legend> <div data-bind="foreach: people"> <div class='row-fluid'> <div class='span5'> <span>First: </span> <input class='input-small' data-bind="value: first, valueUpdate: 'keyup'"/> </div> <div class='offset1 span5'> <span>Last: </span> <input class='input-small' data-bind="value: last, valueUpdate: 'keyup'"/> </div> </div> </div> </div>
people = new Backbone.Collection([{first: 'Jeremy', last: 'Ashkenas'}, {first: 'Steven', last: 'Sanderson'}, {first: 'Kevin', last: 'Malakoff'}]) filtered_names = ko.observableArray(['Kevin']) view_model = filtered_names: filtered_names available_names: ko.observableArray(people.map((model) -> return model.get('first'))) people: kb.collectionObservable(people, {filters: (model) -> return model.get('first') is filtered_names()[0]}) ko.applyBindings(view_model, $('#kbco_filtering')[0])
var ko = kb.ko; var people = new Backbone.Collection([{first: 'Jeremy', last: 'Ashkenas'}, {first: 'Steven', last: 'Sanderson'}, {first: 'Kevin', last: 'Malakoff'}]); var filtered_names = ko.observableArray(['Kevin']); var view_model = { filtered_names: filtered_names, available_names: ko.observableArray(people.map(function(model) { return model.get('first'); })), people: kb.collectionObservable(people, {filters: function(model) { return model.get('first') === filtered_names()[0]; } }) }; ko.applyBindings(view_model, $('#kbco_filtering')[0]);
You can use kb.CollectionObservables to bind HTML select statements using Knockout.js selectOptions.
<div id='kbco_html_select'> <select multiple="multiple" data-bind="options: people, optionsText: 'name', selectedOptions: selected_people"></select> <div> <span>Selected people: </span> <!-- ko foreach: selected_people --> <span data-bind="text: name"></span> <!-- /ko --> </div> </div>
people = new Backbone.Collection([{name: 'Bob'}, {name: 'Sarah'}, {name: 'George'}]) selected_people = new Backbone.Collection() view_model = people: kb.collectionObservable(people) selected_people: kb.collectionObservable(selected_people) ko.applyBindings(view_model, $('#kbco_html_select')[0])
var ko = kb.ko; var people = new Backbone.Collection([{name: 'Bob'}, {name: 'Sarah'}, {name: 'George'}]); var selected_people = new Backbone.Collection(); var view_model = { people: kb.collectionObservable(people), selected_people: kb.collectionObservable(selected_people) }; ko.applyBindings(view_model, $('#kbco_html_select')[0]);
One important constraint is that in order for Knockout.js select bindings to work, the same ViewModel instance needs to be included in each kb.CollectionObservable. You can use shareOptions to share the kb.Store and hence ViewModels between kb.CollectionObservables.
Here is an adapted sample from Knockback Reference App.