Why did I have to set this in the setupController to work?


#1

Hi everyone,

I’ve been having a problem with a real textual multiplayer game in ember. I have a game model like this:

App.Game = DS.Model.extend({
    numbers: DS.attr(),
    drawnNumbers: DS.attr(), // array
    gameStatus: DS.attr(),
    table: DS.belongsTo('table'),
    bingoCards: DS.hasMany('bingoCard')
});

Basically I had a filter in my controller which updates the current bingoCards in a game

   gameBingoCards: function () {
        var gameId;
        gameId = this.get('id');

        console.log("inside gameBingoCards");            

        return this.get('store').filter('bingoCard', function (bingoCard) {
            return (bingoCard.get('game.id') === gameId);
        });
    }.property('model.bingoCards'),

My route looked like this:

model: function (params) {
    return this.store.find('game', params.game_id);
},
setupController: function (controller, model) {
    model.reload();

    controller.set('model', model);
},

Now everytime the model received an update (even unrelated the the bingoCards), the gameBingoCards property also updated.

When changing my route to this:

model: function (params) {
    return this.store.find('game', params.game_id);
},
setupController: function (controller, model) {
    model.reload();

    controller.set('model', model);
    controller.set('modelBingoCards', model.get('bingoCards'));
},

And my controller to this:

    gameBingoCards: function () {
        var gameId;
        gameId = this.get('id');

        console.log("inside gameBingoCards");            

        return this.get('store').filter('bingoCard', function (bingoCard) {
            return (bingoCard.get('game.id') === gameId);
        });
    }.property('modelBingoCards'),

Everytime my game received an update like to gameStatus model.bingoCards got triggered. But when using my solution by declaring the bingoCards in setupController it doesn’t anymore. Why is this?


#2

A couple of things are going on here:

  1. In order for the gameBingoCards property to properly receive change notifications, you need to observe model.bingoCards.[], not just model.bingoCards. This may or may not have had any impact on your application.
  2. By ‘everytime the model received an update’, I think you meant after calling .save() on the game record. If so, then the reason that the gameBingoCards computed property is called again is a side effect of how Ember Data properties work: all model attribute/relation properties are computed properties that are dependent on a pseudo data property that changes every time a record is pushed or saved. So even if the actual relations didn’t change, the bingoCards property gets notified of a change after being saved.
  3. This is the reason that the modelBingoCards property doesn’t get a notification of change: the record array value is now a property on the controller directly, which Ember Data knows nothing about.
  4. Calling model.reload() in setupController is a bit of an anti-pattern, but in the case where you always want to reload the model when hitting this route, you should use the upcoming refresh route method.
  5. It’s just a best practice to call this._super(controller, model); at the top of setupController, in which case you don’t have to manually call controller.set('model', model); because you get it for free.

#3

Thanks a lot for helping my understand what’s happening! I love and hate Ember at the same time, so much frustration when something won’t work as you’d expect and so much joy when something works :smile:.

  1. didn’t help, I’ve tried that.

  2. I meant when receiving an update via websockets like this:

record = serializer.extractSingle(store, type, data);
// record looks like this:
// {id: "538c56843800226245c3621a", gameStatus: "idle"} 
store.update("game", record);
  1. Thanks :smile:
  2. Does the refresh work similar to an actual page reload? Because before implementing my changes the page did work as I want after I did a page refresh (f5).
  3. Should I always call this? Or only if I want controller.set('model', model);?

Again, thanks for taking some time to help me understand.

edit: need to add text to reformat the ordered list “body is too similar”


#4

How about using @each.bingoCards or something like that? Also, make sure you are using an ArrayController


#5

Also, on supers(), i’d be wary of calling that a best practice, best practice would be not to use them at all, but to listen on initialization or something like that. I’d actually use something like controller.set(‘model’) because its more declarative. And technically, shouldn’t you not need to call super since you’re inheriting straight from whatever object(route, controller, etc) you’re using?