Kasper Tidemann
Kasper Tidemann

Reputation: 488

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

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:

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):

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?

Upvotes: 24

Views: 13135

Answers (13)

vvlnv
vvlnv

Reputation: 431

Tested on Ember Data 3.8.0

Just an update to Martin Malinda's answer:

// Clear changed attributes list 
record._internalModel._recordData._attributes = {};

// Trigger transition to 'loaded.saved' state
record.send('pushedData');

In my case I also needed to override serializer's normalize method.

Upvotes: 1

AndreaScn
AndreaScn

Reputation: 121

I work on Ember data 1.13 so I used the following solution (which seems a mix between the one provided by @Martin Malinda and the other by @Serge):

// Ensure you have the changes inside the record
Object.assign(record.data, record._internalModel._attributes);
Object.assign(record._internalModel._data,record._internalModel._attributes);

// Using the DS.State you can first simulate the record is going to be saved
record.get('_internalModel').send('willCommit');

// Cleaning the prevous dirty attributes
record.get('_internalModel')._attributes = {};

// Mark the record as saved (root.loaded.created.uncommitted) even if it isn't for real
record.get('_internalModel').send('didCommit');

In this way, if we will call a further rollbackAttributes() on this record, if we will have some dirty attributes, the record will be reset to this last state (instead of having the original properties) which was exactly what I was looking for in my use case.

If we won't have any dirty attributes, nothing will change and we will keep the last attributes set using this code without having them rolled back to the original ones. Hope it helps.

Upvotes: 1

brayancastrop
brayancastrop

Reputation: 381

Ember 2.9.1

record.set('currentState.isDirty', false);

Upvotes: 3

Martin Malinda
Martin Malinda

Reputation: 1608

Tested on Ember Data 2.9

pushedData action is the way to go but besides that the "originalValues" need to be reset as well.

Ember.assign(record.data, record._internalModel._attributes);
Ember.assign(record._internalModel._data, record._internalModel._attributes);
record.send('pushedData');

Upvotes: 2

Serge
Serge

Reputation: 333

It's an update to @Kamil-j's solution.

For Ember Data 2.0 which I am currently using I have to do the following:

record._internalModel.send('willCommit'); 
record._internalModel._attributes = {};
record._internalModel.send('didCommit');

Upvotes: 7

elatonsev
elatonsev

Reputation: 699

Solution for Ember Data 2.6.1

record.send('pushedData');

set dirty record as loaded and saved

https://github.com/emberjs/data/blob/fec260a38c3f7227ffe17a3af09973ce2718acca/addon/-private/system/model/states.js#L250

Upvotes: 10

Jeff E
Jeff E

Reputation: 181

Another method that worked for me when using Ember Data 1.0.0-beta.18:

record.rollback()

This reversed the dirty attributes and returned the record to a clean state.

Seems like this may have been since deprecated in favor of record.rollbackAttributes: http://emberjs.com/api/data/classes/DS.Model.html#method_rollbackAttributes

Upvotes: 1

Aymerick
Aymerick

Reputation: 51

As of ember-data 1.0.0-beta.12:

record.transitionTo('loaded.saved');

It seems that record.get('stateManager') is not required anymore.

Upvotes: 5

Antti Hukkanen
Antti Hukkanen

Reputation: 41

Here's what seems to work for Ember Data 1.0.0-beta.10:

record.set('currentState.stateName', 'root.loaded.saved');
record.adapterWillCommit();
record.adapterDidCommit();
record.set('currentState.isDirty', false);

Not sure if all those lines are required but just following what others have done prior to this.

Upvotes: 4

Kamil J.
Kamil J.

Reputation: 383

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.

Upvotes: 24

Andriy Buday
Andriy Buday

Reputation: 1969

It looks like with newer versions everything methioned here got broken.

This worked for me with ember-data 1.0.0.beta4:

record.adapterWillCommit();
record.adapterDidCommit();

Upvotes: 1

user160917
user160917

Reputation: 9350

As of 1.0.0.rc6.2....

This will move a model into the state of a model that has been saved.

record.get('stateManager').transitionTo('loaded.saved') 

This will moves a model to a the state of a new model that has not been committed. Think new dirty model.

record.get('stateManager').transitionTo('loaded.created.uncommitted')

This will move a model into the sate of an old model that has been updated, think old dirty model:

record.get('stateManager').transitionTo('loaded.updated')

Upvotes: 5

Loadx
Loadx

Reputation: 250

Looking at ember-data the uncommitted state has a 'becameClean' event which consequently sets the record as loaded.saved.

This should do the trick

record.get('stateManager').send('becameClean');  

Upvotes: 12

Related Questions