Backbone.js is a client-side MV* framework that can do some pretty smart things with data going to and coming back from a server, and has a great event model for keeping multiple views in sync.
This little example shows how Backbone Models and Collections can
work with Handsontable. Below, you'll see events firing from
changes in the CarCollection
by Handsontable or
otherwise.
Make | Model | Year |
---|---|---|
Dodge | Ram | 2012 |
Toyota | Camry | 2012 |
Smart | Fortwo | 2012 |
Please note that Backbone integration is a work in progress since Handsontable 0.8.14. The code presented here has 2 known issues:
alter
method and
the context menu
minSpareRows
does not have effect directly after row was added from Backbone (as a
workaround, you would need to call loadData
instead of render
)
Both issues will be addressed in future versions of HT. Contributions are welcome!
var
container = document.getElementById('example1'),
addCar = document.getElementById('add_car'),
eventHolder = document.getElementById('example1_events'),
CarModel = Backbone.Model.extend({}),
CarCollection,
cars,
hot;
CarCollection = Backbone.Collection.extend({
model: CarModel,
// Backbone.Collection doesn't support `splice`, yet! Easy to add.
splice: hackedSplice
});
cars = new CarCollection();
// since we're not using a server... make up some data. This will make
// a couple CarModels from these plain old objects
cars.add([
{make: 'Dodge', model: 'Ram', year: 2012, weight: 6811},
{make: 'Toyota', model: 'Camry', year: 2012, weight: 3190},
{make: 'Smart', model: 'Fortwo', year: 2012, weight: 1808}
]);
hot = new Handsontable(container, {
data: cars,
dataSchema: makeCar,
contextMenu: true,
columns: [
attr('make'),
attr('model'),
attr('year')
],
colHeaders: ['Make', 'Model', 'Year']
// minSpareRows: 1 //see notes on the left for `minSpareRows`
});
// this will log all the Backbone events getting fired!
cars.on('all', logEvents)
.on('add', function () {
hot.render();
})
.on('remove', function () {
hot.render();
});
// you'll have to make something like these until there is a better
// way to use the string notation, i.e. "bb:make"!
// normally, you'd get these from the server with .fetch()
function attr(attr) {
// this lets us remember `attr` for when when it is get/set
return {data: function (car, value) {
if (_.isUndefined(value)) {
return car.get(attr);
}
car.set(attr, value);
}};
}
// just setting `dataSchema: CarModel` would be great, but it is non-
// trivial to detect constructors...
function makeCar() {
return new CarModel();
}
// use the "good" Collection methods to emulate Array.splice
function hackedSplice(index, howMany /* model1, ... modelN */) {
var args = _.toArray(arguments).slice(2).concat({at: index}),
removed = this.models.slice(index, index + howMany);
this.remove(removed).add.apply(this, args);
return removed;
}
// show a log of events getting fired
function logEvents(event, model) {
var now = new Date(),
option = document.createElement('OPTION');
option.innerHTML = [':', now.getSeconds(), ':', now.getMilliseconds(), '[' + event + ']',
JSON.stringify(model)].join(' ');
eventHolder.insertBefore(option, eventHolder.firstChild);
}
Handsontable.Dom.addEvent(addCar, 'click', function () {
cars.add({make: "Tesla", model: "S", year: 2012, weight: 4647.3});
});