I'm learning and building emberjs app with rails. In this app, I want the data to be pushed rather than polled to the client app.
For.e.g. the following snippet at http://awardwinningfjords.com/2011/12/27/emberjs-collections.html
// Setup a global namespace for our code.
Twitter = Em.Application.create({
// When everything is loaded.
ready: function() {
// Start polling Twitter
setInterval(function() {
Twitter.searchResults.refresh();
}, 2000);
// The default search is empty, let's find some cats.
Twitter.searchResults.set("query", "cats");
// Call the superclass's `ready` method.
this._super();
}
});
It polls twitter API, but my question is how to make an EmberJS app that uses a WebSocket connection to update its state?
You have to implement a DS.Adapter that understands how to handle WebSockets. Here is an simple example:
var SOCKET = 'ws://localhost:9090/some-websocket';
var ID = 'uuid';
var FIND = 'find';
var FIND_MANY = 'findMany';
var FIND_QUERY = 'findQuery';
var FIND_ALL = 'findAll';
/**
* Implementation of WebSocket for DS.Store
*/
App.Store = DS.Store.extend({
revision: 4,
adapter: DS.Adapter.create({
socket: undefined,
requests: undefined,
send: function(action, type, data, result) {
/* Specific to your web socket server side implementation */
var request = {
"uuid": generateUuid(),
"action": action,
"type": type.toString().substr(1),
"data": data
};
this.socket.send(JSON.stringify(request));
/* So I have access to the original request upon a response from the server */
this.get('requests')[request.uuid] = request;
return request;
},
find: function (store, type, id) {
this.send(FIND, type, id);
},
findMany: function (store, type, ids, query) {
this.send(FIND_MANY, type, ids);
},
findQuery: function (store, type, query, modelArray) {
this.send(FIND_QUERY, type, query, modelArray).modelArray = modelArray;
},
findAll: function (store, type) {
this.send(FIND_ALL, type);
},
/* Also implement:
* createRecord & createRecords
* updateRecord & updateRecords
* deleteRecord & deleteRecords
* commit & rollback
*/
init: function () {
var context = this;
this.set('requests', {});
var ws = new WebSocket(SOCKET);
ws.onopen = function () {
};
ws.onmessage = function(event) {
var response = JSON.parse(event.data);
var request = context.get('requests')[response.uuid];
switch (request.action) {
case FIND:
App.store.load(type, response.data[0]);
break;
case FIND_MANY:
App.store.loadMany(type, response.data);
break;
case FIND_QUERY:
request.modelArray.load(response.data);
break;
case FIND_ALL:
App.store.loadMany(type, response.data);
break;
default:
throw('Unknown Request: ' + request.action);
}
/* Cleanup */
context.get('requests')[response.uuid] = undefined;
};
ws.onclose = function () {
};
this.set('socket', ws);
}
});
});
I actually was playing around with the code from that article a few days ago. Keep the handle bar template the same, and use the following code. Obviously, this all depends on what JSON you're passing through the socket. The following code is tried and tested with ntwitter for node.
Twitter = Em.Application.create({
ready: function() {
var socket = io.connect();
socket.on('message', function(json) {
Twitter.searchResults.addTweet(Twitter.Tweet.create(JSON.parse(json)));
});
this._super();
}
});
//Model
Twitter.Tweet = Em.Object.extend();
//Collection
Twitter.searchResults = Em.ArrayController.create({
content: [],
_idCache: {},
addTweet: function(tweet) {
var id = tweet.get("id");
if (typeof this._idCache[id] === "undefined") {
this.pushObject(tweet);
this._idCache[id] = tweet.id;
}
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With