Created
November 27, 2013 17:57
-
-
Save JoshMock/7680146 to your computer and use it in GitHub Desktop.
Fire Backbone model/collection events via websockets using Socket.io. Client code depends on RequireJS for AMD and Cocktail (https://github.com/onsi/cocktail) to apply websocket functionality as a mixin. Assumes views are listening to model/collection changes and updating the DOM accordingly. Some cruft may be specific to the project I'm working…
This file contains hidden or 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
module.exports = function (io) { | |
"use strict"; | |
// set up websockets | |
io.sockets.on('connection', function (socket) { | |
var eventTypes = [ | |
'Backbone.Model.change', | |
'Backbone.Collection.add', | |
'Backbone.Collection.remove', | |
'Backbone.Collection.sort' | |
]; | |
// thin wrapper that broadcasts all Backbone changes to all other sockets | |
eventTypes.forEach(function (type) { | |
socket.on(type, function (data) { | |
socket.broadcast.emit(type, data); | |
}); | |
}); | |
}); | |
}; |
This file contains hidden or 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
define(["backbone", "cocktail", "socket-event-mixin"], function (Backbone, Cocktail, SocketEventMixin) { | |
"use strict"; | |
var MyModel = Backbone.Model.extend({ | |
// stuff | |
}) | |
Cocktail.mixin(MyModel, SocketEventMixin); | |
return MyModel; | |
}); |
This file contains hidden or 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
define(["backbone", "underscore"], function (Backbone, _) { | |
"use strict"; | |
function initModel (model) { | |
model.socketId = _.uniqueId("socketEventModel"); | |
// require App inside fn to prevent a circular dependency | |
require(["app"], function (App) { | |
var socket = App.socket; | |
// publish model events to socket | |
model.on("change", function (changedModel, options) { | |
if (!options.triggeredBySocket) { | |
socket.emit("Backbone.Model.change", { | |
id: model.socketId, | |
updates: model.toJSON() | |
}); | |
} | |
}); | |
// apply socket events to model | |
socket.on("Backbone.Model.change", function (data) { | |
if (data.id === model.socketId) { | |
model.set(data.updates, { triggeredBySocket: true }); | |
} | |
}); | |
}); | |
} | |
function initCollection (collection) { | |
collection.socketId = _.uniqueId("socketEventCollection"); | |
// require App inside fn to prevent a circular dependency | |
require(["app"], function (App) { | |
var socket = App.socket, | |
emitData = { id: collection.socketId }; | |
// publish collection events to socket | |
collection.on("add", function (model, changedCollection, options) { | |
if (!options.triggeredBySocket) { | |
socket.emit("Backbone.Collection.add", _.extend(_.clone(emitData), { | |
model: model.toJSON(), | |
modelSocketId: model.socketId, | |
index: changedCollection.models.indexOf(model) | |
})); | |
} | |
}); | |
collection.on("remove", function (model, changedCollection, options) { | |
if (!options.triggeredBySocket) { | |
socket.emit("Backbone.Collection.remove", _.extend(_.clone(emitData), { | |
modelSocketId: model.socketId | |
})); | |
} | |
}); | |
collection.on("sort", function (changedCollection, options) { | |
if (!options.triggeredBySocket) { | |
socket.emit("Backbone.Collection.sort", _.extend(_.clone(emitData), {})); | |
} | |
}); | |
// apply socket events to collection | |
socket.on("Backbone.Collection.add", function (data) { | |
if (data.id === collection.socketId) { | |
collection.add(data.model, { | |
at: data.index, | |
triggeredBySocket: true | |
}); | |
collection.at(data.index).socketId = data.modelSocketId; | |
} | |
}); | |
socket.on("Backbone.Collection.remove", function (data) { | |
if (data.id === collection.socketId) { | |
var modelToRemove; | |
collection.each(function (model) { | |
if (model.socketId === data.modelSocketId) { | |
modelToRemove = model; | |
} | |
}); | |
collection.remove(modelToRemove, { triggeredBySocket: true }); | |
} | |
}); | |
socket.on("Backbone.Collection.sort", function (data) { | |
// TODO | |
}); | |
}); | |
} | |
return { | |
initialize: function () { | |
if (this instanceof Backbone.Model) { | |
initModel(this); | |
} else if (this instanceof Backbone.Collection) { | |
initCollection(this); | |
} else { | |
throw new Error("This object is not a Backbone.Model or Backbone.Collection"); | |
} | |
} | |
}; | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment