Skip to content

Instantly share code, notes, and snippets.

@tkachenko1503
Forked from colllin/backbone.autorun.js
Last active September 18, 2015 11:45
Show Gist options
  • Save tkachenko1503/5c7fb585641e98f13df9 to your computer and use it in GitHub Desktop.
Save tkachenko1503/5c7fb585641e98f13df9 to your computer and use it in GitHub Desktop.
(function() {
Backbone.Events.autorun = function(f, context) {
if (!this.__autorunHandles) this.__autorunHandles = [];
var backboneContext = this;
var handle = Tracker.autorun(function() {
Tracker.currentComputation.__backboneContext = backboneContext;
f();
});
this.__autorunHandles.push(handle);
return handle;
};
Backbone.Events.stopListening = _.wrap(Backbone.Events.stopListening, function(bbStopListening, subject) {
// If stopListening is called without a subject, stop all running computations.
if (!subject && this.__autorunHandles) {
for (var i = 0; i < this.__autorunHandles.length; i++) {
this.__autorunHandles[i].stop();
}
}
return bbStopListening.apply(this, Array.prototype.slice.call(arguments, 1));
});
_([Backbone, Backbone.Model.prototype, Backbone.Collection.prototype, Backbone.View.prototype, Backbone.Router.prototype, Backbone.History.prototype]).each(function(hasEvents) {
_.extend(hasEvents, {
autorun: Backbone.Events.autorun,
stopListening: Backbone.Events.stopListening
});
});
// Wrap all Backbone.Model accessor functions to establish dependencies on any active computations.
var establishModelDependency = function(model, listener, attr) {
if (!model.__dependencies) model.__dependencies = [];
var dependency = new Tracker.Dependency();
dependency.depend();
var depChanged = function() {
dependency.changed();
};
listener.listenTo(model, attr ? 'change:'+attr : 'change', depChanged);
Tracker.currentComputation.onInvalidate(function() {
listener.stopListening(model, attr ? 'change:'+attr : 'change', depChanged);
});
};
Backbone.Model.prototype.get = _.wrap(Backbone.Model.prototype.get, function reactiveGet(bbGet, attr) {
if (Tracker.active) establishModelDependency(this, Tracker.currentComputation.__backboneContext || this, attr);
return bbGet.apply(this, Array.prototype.slice.call(arguments, 1));
});
Backbone.Model.prototype.toJSON = _.wrap(Backbone.Model.prototype.toJSON, function reactiveToJSON(bbToJSON) {
if (Tracker.active) establishModelDependency(this, Tracker.currentComputation.__backboneContext || this);
return bbToJSON.apply(this, Array.prototype.slice.call(arguments, 1));
});
// Underscore methods that are implemented on the Model.
var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit'];
_(modelMethods).each(function(method) {
Backbone.Model.prototype[method] = _.wrap(Backbone.Model.prototype[method], function(bbMethod) {
if (Tracker.active) establishModelDependency(this, Tracker.currentComputation.__backboneContext || this);
return bbMethod.apply(this, Array.prototype.slice.call(arguments, 1));
});
});
// These accessor functions all rely on `get()`, so any dependencies will be established by `get()`.
// Backbone.Model.prototype.escape
// Backbone.Model.prototype.has
// .isValid() will trigger recomputation as expected if your .validate() function doesn't bypass the accessor functions that establish dependencies for you.
// Backbone.Model.prototype.isValid
// Backbone.Model.prototype.isNew
// // Wrap all Backbone.Collection accessor functions to establish dependencies on any active computations.
// var establishCollectionDependency = function(collection, listener, events) {
// if (!collection.__dependencies) collection.__dependencies = [];
// var dependency = new Tracker.Dependency();
// var depChanged = function() {
// dependency.changed();
// };
// listener.listenTo(collection, events, depChanged);
// dependency.depend();
// Tracker.currentComputation.onInvalidate(function() {
// listener.stopListening(collection, events, depChanged);
// });
// };
// Backbone.Collection.prototype.toJSON = _.wrap(Backbone.Collection.prototype.toJSON, function(bbToJSON) {
// if (Tracker.active) establishCollectionDependency(this, Tracker.currentComputation.__backboneContext || this, 'add change remove reset');
// return bbToJSON.apply(this, Array.prototype.slice.call(arguments, 1));
// });
// // Underscore methods that are implemented on the Collection.
// var collectionMethods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
// 'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
// 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
// 'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
// 'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle',
// 'lastIndexOf', 'isEmpty', 'chain', 'sample'];
// _(collectionMethods).each(function(method) {
// Backbone.Collection.prototype[method] = _.wrap(Backbone.Collection.prototype[method], function(bbMethod) {
// if (Tracker.active) establishCollectionDependency(this, Tracker.currentComputation.__backboneContext || this, 'add remove reset');
// })
// })
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment