Skip to content

Instantly share code, notes, and snippets.

@juliocesar
Created April 8, 2011 00:44
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save juliocesar/909090 to your computer and use it in GitHub Desktop.
Save juliocesar/909090 to your computer and use it in GitHub Desktop.
Backbone.js localStorage if specified
// Generate four random hex digits.
function S4() {
return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
};
// Generate a pseudo-GUID by concatenating random hexadecimal.
function guid() {
return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
};
// Our Store is represented by a single JS object in *localStorage*. Create it
// with a meaningful name, like the name you'd give a table.
var Store = function(name) {
this.name = name;
var store = localStorage.getItem(this.name);
this.data = (store && JSON.parse(store)) || {};
};
_.extend(Store.prototype, {
// Save the current state of the **Store** to *localStorage*.
save: function() {
localStorage.setItem(this.name, JSON.stringify(this.data));
},
// Add a model, giving it a (hopefully)-unique GUID, if it doesn't already
// have an id of it's own.
create: function(model) {
if (!model.id) model.id = model.attributes.id = guid();
this.data[model.id] = model;
this.save();
return model;
},
// Update a model by replacing its copy in `this.data`.
update: function(model) {
this.data[model.id] = model;
this.save();
return model;
},
// Retrieve a model from `this.data` by id.
find: function(model) {
return this.data[model.id];
},
// Return the array of all models currently in storage.
findAll: function() {
return _.values(this.data);
},
// Delete a model from `this.data`, returning it.
destroy: function(model) {
delete this.data[model.id];
this.save();
return model;
}
});
// Override `Backbone.sync` to use delegate to the model or collection's
// *localStorage* property, which should be an instance of `Store`.
var $super = Backbone.sync;
if ('localStorage' in window) {
Backbone.sync = function(method, model, options) {
var resp, store = model.localStorage || (model.collection && model.collection.localStorage);
if (typeof store === 'undefined') return $super(method, model, options);
switch (method) {
case "read": resp = model.id ? store.find(model) : store.findAll(); break;
case "create": resp = store.create(model); break;
case "update": resp = store.update(model); break;
case "delete": resp = store.destroy(model); break;
}
if (resp) {
options.success(resp);
} else {
options.error("Record not found");
}
};
}

Backbone.js Todos example app comes with a nifty localStorage adapter which allows Backbone to transparently save data locally. That's all kinds of awesome, however, the way it's written, it overrides Backbone.sync globally, so you're left with localStorage as your only option.

This small change I made to it ensures that only when you extend a model or a collection with localStorage as a parameter, that model/collection in particular will be local while everything else works normally.

Note that this line here

if ('localStorage' in window)

ensures that it'll only work in browsers that support the localStorage API. _You'd be better off testing that with yepnope.js and loading this feature conditionally).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment