EmberJS: Loading a child URL directly in a master-detail app with an SSE-backed model on the master controller

StackOverflow https://stackoverflow.com/questions/23483313

Question

I'm trying to develop this single-module application with a master-detail relationship between two routes. The master is supposed to have a model which is initially loaded and subsequently updated with a single Server-Side-Events entry point. I have the following code so far:

var App = Ember.Application.create({
    rootElement: '#content'
});

App.Router.map(function() {
    this.resource('receptores', {path: '/'}, function() {
        this.resource('receptor', {path: ':user_id'});
    });
});

App.ReceptoresController = Ember.Controller.extend({
    init: function() {
        var sse = new EventSource('/push');
        var controller = this;
        sse.addEventListener('update-hhs', function(e) {
            controller.set('model', JSON.parse(e.data).receptores);
        });
    }
});

App.ReceptorRoute = Ember.Route.extend({
    model: function(params) {
        return this.modelFor('receptores').findBy('id', params.user_id);
    }
});

Loading the 'receptores' works and currently the data loads fine. Clicking on a link-to generated link as http://localhost:5003/#/skkkd, for example, will load the 'receptor' route and the detail data as well (the detail is just a subset of the same data loaded on the master).

If I try reloading at a detail url or entering http://localhost:5003/#/skkkd directly I'll get the following exception:

Error while loading route: TypeError: Cannot read property 'findBy' of undefined
    at App.ReceptorRoute.Ember.Route.extend.model (http://localhost:5003/monitoreo/static/js/receptores.js:34:43)
    at superWrapper [as model] (http://localhost:5003/static/js/ember-1.5.1.js:1292:16)
    at Ember.Route.Ember.Object.extend.deserialize (http://localhost:5003/static/js/ember-1.5.1.js:36570:19)
    at http://localhost:5003/static/js/ember-1.5.1.js:32972:57
    at http://localhost:5003/static/js/ember-1.5.1.js:33464:19
    at invokeResolver (http://localhost:5003/static/js/ember-1.5.1.js:9646:9)
    at new Promise (http://localhost:5003/static/js/ember-1.5.1.js:9632:9)
    at Router.async (http://localhost:5003/static/js/ember-1.5.1.js:33463:16)
    at Object.HandlerInfo.runSharedModelHook (http://localhost:5003/static/js/ember-1.5.1.js:32971:16)
    at Object.UnresolvedHandlerInfoByParam.getModel (http://localhost:5003/static/js/ember-1.5.1.js:33058:19) 

I know the problem is the init hook isn't being called for ReceptoresController. I think what I should do is implement a model hook on either a ReceptoresRoute or the controller and load initial data through a jQuery.get() and have the server-side-events only update. But then where do I initialize the SSE?

Edit: It turns out I misunderstood how the model hook works on child routes. In my case, I normally view the detail page through a link-to link, so Ember already provides the model for receptor. The model hook is never called in that case. It is only called when trying to access the detail page directly which is where it fails. So my problem remains.

My whole problem boils down to where I should place the SSE initialization so that both routes can have access to the same model regardless of which was loaded.

Was it helpful?

Solution

Alright, this is my solution. Pieced together from a couple questions here. Namely https://stackoverflow.com/a/21988143/410224 and https://stackoverflow.com/a/21752808/410224. Hope it helps someone out.

var App = Ember.Application.create({
    rootElement: '#content'
});

App.Router.map(function() {
    this.resource('receptores', {path: '/'}, function() {
        this.resource('receptor', {path: ':user_id'});
    });
});

App.ReceptoresRoute = Ember.Route.extend({
   model: function() {
       var deferredData = Ember.Deferred.create();
       var data = [];
       var sse = new EventSource('/push');
       sse.addEventListener('update-hhs', function(e) {
           var receptores = JSON.parse(e.data).receptores;
           receptores.forEach(function(r) {
               var item = data.findBy('id', r.id);
               if (typeof(item) != 'undefined') {
                   data.replace(data.indexOf(item), 1, [r]);
               } else {
                   data.pushObject(r);
                   data.sortBy('full_name');
               }
           });
           deferredData.resolve(data);
       });
       return deferredData;
   }
});

App.ReceptorRoute = Ember.Route.extend({
    model: function(params) {
        return this.modelFor('receptores').findBy('id', params.user_id);
    }
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top