Observe reload/changes to model

I am using ember-changeset for all my validation needs. The thing is that the changeset needs to be initialised with the current model. So, usually this is done in the route::setupController() method. This all works fine. Unless you are using a web socket and the server pushes updated records, which get pushed to the ember store via pushPayload(). What happens now is that a user that is viewing the record that is updated, does not see the changes, as the user only sees the current changeset (and not the actual model), wich gets updated whenever the setupController() method in the route is called.

Now I am looking for a way to observe changes to a model that gets pushed to the store. I tried to observe the various properties on the model like isReloading or didUpdate from the controller, but I wasn’t able to get it to fire when the model is updated. The only solution I have found so far is to observe all properties I know that would change when an updated model is pushed, which seems quite cumbersome.

Is there a way to observe when an updated model is pushed to the store?

1 Like

This may be a tad naive of me but have you tried just watching the model with a computed property and recreating the changeset? For instance something like:

  user: alias('model')

  changeset: computed('user', function() {
    return new Changeset(get(this, 'user'), SomeValidations);
  })

When the model changes (in this case its a single record but you could drill down) it will update the changeset. You could also update the changeset while keeping values previously inputted by the user by applying them before returning the changeset.

Thanks for the reply. I just tried, but no luck so far. I think this approach has the same issue than just watching the model directly. There is no observer triggered, as observing the model does not observe any properties the model consists of. So, I can make that work the same way I did when observing the model instead of an alias (by observing the actual properties that change within the alias instead of the alias itself):

user: alias('model')

changeset: computed('user.name', 'user.title', ... , function() {
  return new Changeset(get(this, 'user'), SomeValidations);
})

From an ember data perspective I guess there might be two solutions:

  • watch every property in the model
  • use a hook or property that is triggered when the updated record is pushed to the store

The first solutions has a little sideeffect without additional code: It gets triggered n times when entering the route, where n is the number of properties on the model, which leads to n changesets created.

Well it took a little fiddling but I managed to get it working. You can pass your record (a javascript object) to Embers defineProperty function and generate a computed prop for each key in the record like so :

for (let k in get(this, 'user')) {
  defineProperty(this, `user.${k}`, computed(`user.${k}`, function() {
    // Do something generic
  }));
}

I created an ember twiddle with a basic version of this working. I never found the official doc for the function but you can read about it in a blog post here or jump straight to their jsbin.

Hope that helps :slight_smile:.

1 Like

@James-Byrne thanks for taking the time. That might actually be an interesting idea for a workaround, as the computed property could be created after the model is loaded, so it won’t trigger when the model is initialised. But it still is a workaround.

I think by now I should probably rephrase my initial question as I like to solve issues at their root:

  • is there a way in ember data to get notified when a new version of the record is pushed to the store? judging by this thread and my search, there is none
  • why isn’t there such a hook? it seems like it wouldn’t be very complex to implement and its seems to be pretty useful, so probably there is a good reason for not doing so
  • should we have such a hook in ember data? I think yes, but hopefully someone from the ember data team will chime in and elaborate.

This isn’t my forte but they’ve implemented something like what you’re describing in EmberFIre (if you’re not familiar with firebase, EmberFire is the Ember addon for firebase which uses websocket connections to hit a “real time” database). Maybe that (either the code or the issues/PRs) could be a resource for you.

Thanks @dknutsen. That hint was quite helpful. Looks like they currently are dealing with that issue as well: https://github.com/firebase/emberfire/issues/497

There also seems to be an open ember data issue for quite a while now https://github.com/emberjs/data/issues/3748

Hopefully someone will chime in at least providing a reason for the current behaviour. At least the ember fire issue seems to provide a useable workaround.

1 Like