Server
var http = require('http'),
io = require('socket.io');
server = http.createServer(function(req, res){
// your normal server code
res.writeHead(200, {'Content-Type': 'text/html'});
res.end('<h1>Hello world</h1>');
});
server.listen(80);
// socket.io
var socket = io.listen(server);
socket.on('connection', function(client){
// new client is here!
client.on('message', function(){ … })
client.on('disconnect', function(){ … })
});
Friday, May 6, 2011
Client
<script src="http://{node_server_url}/socket.io/socket.io.js"></script>
<script>
var socket = new io.Socket({node_server_url});
socket.connect();
socket.on('connect', function(){ … })
socket.on('message', function(){ … })
socket.on('disconnect', function(){ … })
</script>
Friday, May 6, 2011
Backbone gives you Observable
Models & Collections
var App = Backbone.Model.extend({
initialize: function () {
this.bind(‘change:myProperty’, _(this.writeIt).bind(this));
},
writeIt: function () {
console.log(“my prop is: “ + this.get(‘myProperty’));
}
});
app = new App();
app.set({myProperty: true}); // outputs: “my prop is: true”
Friday, May 6, 2011
Views just listen to model changes
var AppView = Backbone.Model.extend({
initialize: function () {
this.model.bind(‘change’, _(this.render).bind(this));
},
render: function () {
this.el.html(ich.app(this.model.toJSON()));
return this;
}
});
var app = new App(); // init our model
var appView = new AppView({ model: app, el:
document.body }); // init our view
appView.render();
app.set({myProperty: true}); // will re-render the whole app
Friday, May 6, 2011
Backbone.js
+
model nesting
+
serialization
+
event bubbling
Friday, May 6, 2011
Models shared by Server + Client
(function () {
... detect and set up environment for CommonJS or browser here
// Main app model
exports.AppModel = Capsule.Model.extend({
type: 'app',
initialize: function (spec) {
this.register();
this.addChildCollection('members', exports.Members);
this.addChildModel('activityLog', exports.ActivityLogPage);
}
});
// other models
exports.Members = ...
})();
Friday, May 6, 2011
Server-side
socket.on('connection', function (client) {
var app, sessionId;
// this is split out so we have a reference to it
function sendClientChanges(changes) { client.send(changes); }
client.on('message', function(message){
var model, collection;
switch (message.event) {
case 'session':
...
// Here you'd fetch your user from DB based on sessionid
// you'd also get the corresponding app state that they should have access to.
// `require` your shared models file and inflate or instantiate your root app model
// Then grab whatever else you need and send the intial state to the client.
client.send({
event: 'initial',
app: app.xport()
});
// bind to the root `publish` events to send any changes to this client
app.bind('publish', sendClientChanges);
...
Friday, May 6, 2011
Clientside
$(function () {
var app = window.app = new AppModel();
window.socket = new io.Socket();
// get and send our session cookie
socket.on('connect', function() {
socket.send({
event: 'session',
cookie: $.cookie('&!')
});
});
socket.on(‘message’, ...
});
Friday, May 6, 2011
Clientside cont...
socket.on('message', function (msg) {
switch (msg.event) {
case 'initial':
//import app state
app.mport(msg.app);
// init and render our root view
view = window.view = new AppView({
el: $('body'),
model: app
}).render();
break;
case 'change':
app.modelGetter(msg.id).set(msg.data);
break;
... other cases for `add`, `remove` etc.
}
});
Friday, May 6, 2011
Challenges
• Partially shared state
Hint, sync everything, have your
view render what’s relevant
• Scaling
• Providing external APIs
Friday, May 6, 2011
Thank you!
Helpful Resources:
me on twitter: @HenrikJoreteg (hit me up for early invite to &!)
Backbone.js: http://documentcloud.github.com/backbone/
Capsule.js: https://github.com/andyet/capsule
App Testing: http://funcunit.com,
http://mwbrooks.github.com/dominator.js/
Friday, May 6, 2011