Created
July 20, 2012 08:56
-
-
Save lukecanvin/3149717 to your computer and use it in GitHub Desktop.
Online/offline syncing for Backbone
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Backbone.serverSync = Backbone.sync; | |
Backbone.pingUrl = '/Ping'; | |
Backbone.localID = function() { | |
var localID = (localStorage.localID ? parseInt(localStorage.localID) : 0); | |
localID++; | |
localStorage.localID = localID.toString() | |
return -localID; | |
} | |
Backbone.onLine = function () { | |
var check = (localStorage.onLine ? JSON.parse(localStorage.onLine) : { status: null, lastTested: new Date(1900, 1, 1) }); | |
return check.status; | |
} | |
Backbone.localCache = function (collection, action) { | |
var pushAlso = false; | |
if (action == null) { | |
action = 'pull'; | |
pushAlso = true; | |
} | |
if (action === 'push') { this.localCachePush(collection); } | |
if (action === 'pull') { this.localCachePull(collection, pushAlso); } | |
} | |
Backbone.localCachePush = function (collection) { | |
console.log('LocalCachePush'); | |
//Are there any models unpushed? | |
var models = collection.models; | |
var unpushed = false; | |
for (var i = 0; i < models.length; i++) { | |
if (!models[i].get('synchronized')) { unpushed = true; break; } | |
} | |
if (!unpushed) { return; } | |
$.ajax( | |
{ | |
url: Backbone.pingUrl, | |
type: 'POST', | |
data: "", | |
success: function () { | |
Backbone.localCachePush_(collection); | |
}, | |
error: function () { | |
console.log('Offline'); | |
} | |
}); | |
} | |
Backbone.localCachePush_ = function (collection) { | |
if (collection.localCacheActive) { | |
console.log('LocalCache already active for this collection - aborting...'); | |
return; | |
} | |
//Upload results to server | |
//var models = tempCollection.models; | |
var models = collection.models; | |
for (var i = 0; i < models.length; i++) { | |
var model = models[i]; | |
if (model.get('synchronized')) { continue; } | |
model.change(); | |
Backbone.serverSync('update', model, { | |
success: function (data) { | |
//console.log(data); | |
var model = collection.get(data.ClientId); | |
//if new server will return a different Id | |
if (data.ServerId != data.ClientId) { | |
//delete from localStorage with current Id | |
console.log('Deleting model Id ' + model.get('Id') + ' from local storage'); | |
Backbone.sync("delete", model, { success: function () { }, error: function () { } }); | |
//save model back into localStorage | |
model.save({ Id: data.ServerId }) | |
console.log('Added model Id ' + model.get('Id') + ' to local storage'); | |
} | |
model.save({ synchronized: true }); | |
collection.localCacheActive = false; | |
}, | |
error: function (jqTHX, textStatus, errorThrown) { | |
console.log('Model upload failure:' + textStatus); | |
collection.localCacheActive = false; | |
} | |
}); | |
} | |
} | |
Backbone.localCachePull = function (collection, pushAlso) { | |
console.log('LocalCachePull'); | |
if (Backbone.onLine() === false) { return; } | |
if (collection.localCacheActive) { | |
console.log('LocalCache already active for this collection - aborting...'); | |
return; | |
} | |
collection.localCacheActive = true; | |
//save any unpushed local changes into local storage | |
var models = collection.models; | |
for (var i = 0; i < models.length; i++) { | |
var model = models[i]; | |
model.collection = collection | |
if (!model.get('synchronized')) { | |
console.log('Saving model Id ' + model.get('Id') + ' to local storage'); | |
model.change(); | |
model.save(); | |
} | |
} | |
//create temporary collection to store pulled results | |
var CollectionType = collection.constructor; | |
var tempCollection = new CollectionType(); | |
tempCollection.sync = Backbone.serverSync; | |
//fetch results from server | |
tempCollection.fetch( | |
{ | |
success: function () { | |
console.log("Downloaded " + tempCollection.models.length + " models"); | |
//save new pulled items into collection and local storage | |
tempCollection.sync = Backbone.sync; | |
var tempModels = tempCollection.models; | |
var models = collection.models; | |
var newCount = 0; | |
var updateCount = 0; | |
for (var i = 0; i < tempModels.length; i++) { | |
var tempModel = tempModels[i]; | |
var found = false; | |
for (var j = 0; j < models.length; j++) { | |
model = models[j]; | |
if (tempModel.get('Id') == model.get('Id')) { found = true; break; } | |
} | |
if (!found) { | |
//tempModel is new | |
newCount++; | |
console.log('New model ' + tempModel.get('Id')); | |
collection.add(tempModel); | |
//console.log(tempModel.collection); | |
tempModel.change(); | |
tempModel.save({ synchronized: true }); | |
} | |
else if (model.get('synchronized')) { | |
//client believes it is up-to-date with server | |
//update client | |
console.log('Updating model ' + tempModel.get('Id')); | |
model.set(tempModel.toJSON()); | |
model.set({ synchronized: true }); | |
model.save(); | |
} | |
} | |
console.log("Downloaded models - new: " + newCount); | |
collection.localCacheActive = false; | |
//push if required | |
if (pushAlso) { Backbone.localCachePush(collection); } | |
}, | |
error: function (jqTHX, textStatus, errorThrown) { | |
collection.localCacheActive = false; | |
console.log("Collection download failure: " + textStatus); | |
} | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment