How to manually set an object state to clean (saved) using ember-data

Kasper Tidemann picture Kasper Tidemann · Nov 12, 2012 · Viewed 12.2k times · Source

Explanation:

I'm using ember-data for a project of mine and I have a question that revolves around the possibility of dirtying an object and then setting its state to clean again on purpose - without commiting the changes. The scenario is this:

Say I've fetched an object via banana = App.Fruit.find('banana'); and it has a description of "Yellow fruit!". Using XHR long-polling (or WebSockets), I may receive an updated version of the object because of another user having changed the description to "A tasty yellow fruit!" at any given point in time after I fetched the original object.

Then, what I would like to do is to update the object to reflect the newly received data. For this, I've tried different approaches:

  • I've tried calling App.Store.load(App.Fruit, new_data);. First of all, this approach doesn't work and secondly, this is not really what I want. I could've made uncommitted changes to the object myself and in this case, it would be undesirable to just discard those (assuming the load() call would overwrite them).

  • I've tried looping through the new data, calling .set() - like so: banana.set('description', new_data.description); - in order to update the object properties with the new data (where applicable = not dirty). This works but it leaves the object in a dirtied state.

In order to make the object clean/updated again - and not have the adapter commit the changes! - I've taken a look at the states the object travels through. These are (at least):

  • Step 1: Initially, the object is in the rootState.loaded.saved state.
  • Step 2: Calling .set() on a property pushes it to the rootState.loaded.updated.uncommitted state.
  • Step 3: Calling App.store.commit(); returns the object to the rootState.loaded.saved state.

Therefore, I've tried to manually set the object state to saved after step 2 like so: banana.get('stateManager').goToState('saved');.

However, this doesn't work. The next time the store commits for any other reason, this maneuver produces an inFlightDirtyReasons is undefined error.

Question:

My question is: how can I manually change the state of a dirtied object back to clean (saved) again?

Answer

Kamil J. picture Kamil J. · Apr 28, 2014

Solution for Ember Data 1.0.0-beta.7:

// changing to loaded.updated.inFlight, which has "didCommit" 
record.send('willCommit'); 
// clear array of changed (dirty) model attributes
record.set('_attributes', {});
// changing to loaded.saved (hooks didCommit event in "inFlight" state)
record.send('didCommit');

I've searched the source code of Ember-data and I've found that loaded.saved state has a setup function that checks whether a model is clean, before setting "saved" state. If it is not clean, then it rejects a request to change state and returns to loaded.updated.uncommitted.

So you have to clean model._attributes array, which keeps attributes names and Ember will let you change state manually.

I know it isn't very good solution, because is needed to set private property of a model, but I've not found any other solutions yet.