18

I've been poking around and I can't find any up to date examples of ember (1.0.0-rc.1) and ember-data(revision 11) that also use socket.io. I've tried something like this.

App.ApplicationRoute = Ember.Route.extend({
  setupController: function(controller, data) {
    var socket = io.connect(),
        self = this;
    socket.on('apartment/new', function(apartment) {
      var apt = App.Apartment.createRecord(apartment);
      self.controllerFor('apartments').pushObject(apt);
    });
  }
});

This actually will create a new model class, it pushes the object to the controller, and creates a new li but the values do not render.

<ul class="list-view">
{{#each apartment in controller}}
    <li>
      {{#linkTo 'apartment' apartment }}
        <span class="date">{{date apartment.date}}</span>
        {{apartment.title}}
      {{/linkTo}}
    </li>
{{/each}}
</ul>

Does this have something to do with the run loop? How do force the values to render? Or is there a better approach to this?

user2431285
  • 651
  • 11
  • 19
Chad
  • 16,774
  • 8
  • 29
  • 41

2 Answers2

15

There's a very simple solution to this which I'm using in some of my apps. You can either have a general purpose callback for the socket and accept any kind of data

callback: function(message) {
  // this is better than just `eval`
  var type = Ember.get(Ember.lookup, message.type);
  store.load(type, message.data);
}

or here it is specifically tailored to your use case

socket.on('apartment/new', function(apartment) {
  store.load(App.Apartment, apartment);
});

using store.load will load the record data directly into the identity map. There's also loadMany for loading multiple records.

Jakub Arnold
  • 79,807
  • 86
  • 218
  • 314
  • are we supposed to use **store.load(App.Apartment, apartment)** or **store.get('adapter').load(store, App.Apartment, apartment)**. I just want to be sure of the way to load the data based on the issue you raised in **[issue 649](https://github.com/emberjs/data/issues/649)** and a response to **[a similar question on stackover](http://stackoverflow.com/questions/14899224/how-do-you-automatically-serialize-and-load-an-ember-data-object-from-a-json-res)**. Are my missing something in my understanding. Thanks. – brg Mar 16 '13 at 11:27
  • I am using `store.load(App.Appartment, data)` in the latest ember and it works fine :) Let me know if you have any issues with it, the github issue is old and outdated. – Jakub Arnold Mar 16 '13 at 12:13
  • This results in the same problem that I'm having (just an empty record being placed in the document). Also you need to have a reference to `store` using `var store = this.get('store');` – Chad Mar 16 '13 at 12:16
  • @Chad how exactly does the data you're loading look? – Jakub Arnold Mar 16 '13 at 12:19
  • `apartment : {...}`. It's just object record not an array record. – Chad Mar 16 '13 at 12:23
  • @Chad that's wrong, since you're already specifying it's `App.Apartment` you should just give it the flat data, not the whole `apartment: { ... }`, but only the `{ ... }` – Jakub Arnold Mar 16 '13 at 13:15
  • Gotcha. Got it working now. Is there an equal to `unshift()` for the store so that data is pushed to the beginning of the list? – Chad Mar 16 '13 at 13:33
  • @chad do you want to accept the answer if works, so that anyone searching in future will know atleast this worked as of today. – brg Mar 16 '13 at 14:27
  • I accepted the answer and submitted some edits to @JakubArnold. After further investigation I don't think there is a method on the store by default that allows you to `unshift()` on to other records in the ArrayController's model. – Chad Mar 16 '13 at 14:56
  • In the latest ED (1.1.2) I think you need to use `store.pushPayload(type, payload)` and that inserts raw data. The api says it's push, but in the code is pushPayload. – knownasilya Nov 12 '13 at 12:32
1

Ember CLI, ember sockets, and coffescript

I've only been working with Ember for about a month, so no promises that this is the best way of doing this, but I've had to set up an Ember CLI project with Socket.io and Ember Data. The following is based on my working code, though the following is not tested. I think everything you need to get 99% of the way is here. Good luck troubleshooting!

.jshintrc - Ember service is going to yell at you if you don't include EmberSockets here

{
  "predef": {
  "document": true,
  "window": true,
  "nameofprojectENV": true,
  "EmberSockets": true
  },
  ...
}

Brocfile.js - Import Ember Sockets

var EmberApp = require('ember-cli/lib/broccoli/ember-app');

var app = new EmberApp();

// change this path to where ember-sockets.js is
app.import('vendor/ember-sockets/package/ember-sockets.js');

module.exports = app.toTree();

app.js - remember to replace nameofproject with actual project name

import Ember from 'ember';
import Resolver from 'ember/resolver';
import loadInitializers from 'ember/load-initializers';

Ember.MODEL_FACTORY_INJECTIONS = true;

// every controller using ember sockets must be listed here in the controllers array
var Socket = EmberSockets.extend({
    host: 'example.local',
    port: 8080,
    controllers: [
        'example'
        // more controllers here
    ]
});

var App = Ember.Application.extend({
    modulePrefix: 'nameofproject',
    Resolver: Resolver,
    Socket: Socket
});

loadInitializers(App, 'nameofproject');

export default App;

router.coffee - remember to replace nameofproject with actual project name

`import Ember from 'ember'`

Router = Ember.Router.extend
    location: nameofprojectENV.locationType

Router.map ->
    @route 'example'

`export default Router`

models/example.coffee

`import DS from 'ember-data'`

Example = DS.Model.extend
    name: DS.attr('string')

`export default Example`

routes/example.coffee

`import Ember from 'ember'`

ExampleRoute = Ember.Route.extend
    # set model to be all example records
    model: ->
        @store.all('example')

    setupController: (controller, model) ->
        controller.set('model', model)

`export default ExampleRoute`

controllers/example.coffee

`import Ember from 'ember'`

ExampleController = Ember.Controller.extend

#### properties

examples: (->
    # @get('content') gets the model, which in this case, is example (set in route)
    @get('content')
).property('content') # watching the model like this might not be right?

#### methods
getExamples: ->
    @socket.emit 'pub',
        # whatever data you need to pass to the server
        data : {examples: true}
        # name of the event you want the data returned on
        event: "getExamples"

#### sockets
sockets:
    # returns examples from server
    getExamples: (data) ->
        # log the data for fun, also to see that you are getting data back
        console.log data
        # set controller to @, which is the same as this.
        controller = @

        # get your array of examples from JSON returned from server
        examples = data.examples

        examples.forEach (example) ->
            # controller instead of @, or it doesn't work
            controller.store.push 'example',
                # you need ids or this will not work
                id: example.id
                name: example.name

`export default ExampleController`

templates/example.coffee

{{#each example in examples}}
    {{example.id}} {{example.name}}
{{/each}}

<button {{action getExamples}}>Get Examples</button>

I would suggest the Chrome Ember Inspector for troubleshooting. You can also see your data models and records, among other things.

GJC
  • 31
  • 2