How to undo changes to a model? - ember.js

Is it possible to revert the model to a clean state? I mean undo all the changes to its properties and mark the state as being clean?

Ember-Data now has an awesome implementation of this. They utilize the transaction class to manage the changes to your objects, which imo is the right place for this. To rollback changes on a model:
Obtain the Model
// if PostController is a ArrayController or ArrayProxy
p = App.PostController.objectAt(0);
Get the object's associated transaction instance and call it's rollback() method.
p.get("transaction").rollback();

From Ember 2.0 this is the way to go (once you have got your model object 'model'):
model.rollbackAttributes();
See https://guides.emberjs.com/v2.0.0/models/creating-updating-and-deleting-records/

There is an open PullRequest by Paul Chavard #tchak, see https://github.com/emberjs/data/pull/176

UPDATE: works with ember version <= 1.13
this.get('model').rollback();
see similar question: Revert change to ember data model

Related

Ember Data Snapshot and how to detect changes?

I'm writing my own adapter/serializer. In order to send data to backend, I have to detect changes in DS.Snapshot and original Ember object. For ordinary attributes, it is possible to changedAttributes() but I did not found a way how to detect changes in hasMany relations.
I can detect new relation using snapshot.hasMany('foo') and changedAttributes(). But this approach is not able to find deleted relations.
Ember (2.x) does not track relations (e.g. hasMany) but it is possible to use ember-addon ember-data-change-tracker that can almost do it. It allows you to (auto-)save the current state of relations and afterwards you can compare this 'saved' (=old state) with the current state. You have to find a difference by yourself. A simple example from adapter:
snapshot.hasMany('users').length <-- current count of relations
snapshot.record.savedTrackerValue('users').length <-- old count of relations
Thanks to Christoper for pointing me to the right direction.

Does Ember Model attributes support default value?

I know that Ember Data attributes can have default values with defaultValue property but does Ember Model support this? If so, how?
It doesn't support default values as of yet. If you really needed to use ember model and still wanted this functionality, you could extend the adapter your using to handle it, or if you are only using the model in a single route you could fix up the model in the afterModel hook (I don't like that idea, because if you ever use that model anywhere else you're hosed). I'd probably modify the ember model code and submit a PR if you can't use ember data. Sorry

What is the different between Ember-data Store's currentTransaction and defaultTransaction?

General question:
I would like to get an overview of current transaction (currentTransaction) and default transaction (defaultTransaction).
Specific question:
I've been comparing in the Ember controller this.get('model').save() and this.get('store').commit().
this.get('model').save() will eventually call Ember-data Store's get(this, 'currentTransaction').commit()., see github.
this.get('store').commit() will eventually call Ember-data Store's get(this, 'defaultTransaction').commit(), see github.
In the cases of updating a single edited record, they seem to be exactly the same. How should they be used differently?
I would like to get an overview of current transaction (currentTransaction) and default transaction (defaultTransaction)
currentTransaction is for records that were scheduled to be persisted, typically via model.save()
defaultTransaction is for persisting records that were not explicitly added to another transaction
In the cases of updating a single edited record, they seem to be exactly the same. How should they be used differently?
In that case they are going to do the same thing.
In general model.save() is probably a better choice, since 1) it wont have unexpected side-effects if there are other unsaved records and 2) calling save() on multiple models will result in just one commit(), making batch save possible.
Somewhat related:
Difference between model.save() versus model.get('store').commit()

Ember: how do you access the model from the router?

Based on what I've read (please correct me if I'm mistaken), the logic that handles when a model should be saved and where to transition next should be in the router.
If that is the case, I'm running into a bit of a problem: I don't know how to access the model from the route.
This is my controller (and the console logs "CREATED" after I press submit):
App.ScoutsNewController = Ember.ObjectController.extend
submit: ->
model = #get('model')
model.on 'didCreate', ->
console.log 'CREATED' # I want to redirect to the index after creation
model.save()
I should move that logic into the route, right? Let's try that:
App.ScoutsNewRoute = Ember.Route.extend
model: ->
App.Scout.createRecord()
events:
submit: ->
# Based on what I've read, the right place to put the code you see in the controller is here. How do I get access to the model?
# I have tried #get('model'), #get('content')
Note: I understand that the submit event bubbles up from the view, to the controller, then finally the route, stopping at any one of them that has "submit" defined. So since I want the route to handle it, I removed the controller. I'm able to see any console.log done in the route, I just need to be able to get to the model instance.
I'm using Ember v1.0.0-rc.5-7-g610589a
Thanks!
Two options: this.currentModel or this.modelFor(routeName)
Update
I spoke to SeƱor Alex Matchneer about this. There are no plans for this.currentModel to go away anytime soon, but he considers this.modelFor(this.routeName) the public API.
what should work is
this.controllerFor('ScoutsNew').get('content')
this.currentModel isn't really the approved way as described here
but in my version of Ember (1.11) this.modelFor(this.routeName) returns null, so this is what worked for me
this.controllerFor(this.routeName).get('model')
You could also use this.controller.get('model'); but there are plans to remove the controller.
Till that we can use the above code to retrieve the routes current model
With Ember 3.0.0 this is a documented way that works for me:
const model = this.controller.model;

Revert change to ember data model

Is there a way to revert a change to an Ember Data model easily?
I have a model bound to an edit view. This view enables the user to cancel editing, at which point I'd like to revert the changes to the model. Is there an easy way to do this without cloning all the values off the side?
Starting from Ember Data version 2, there are not transactions anymore, but you can reset models to their last status before saved editions with:
model.rollbackAttributes();
Ember Data supports the concept of transactions. We can create a transaction and assign Ember data records to them and if we want to undo the changes we can call the transactions rollback() method. Also if we do not create an explicit transaction the records are assigned to a default transaction which can be rolled back by calling the rollback() method on the DS.store object itself.
The name of the default transaction is named 'defaultTransaction'. In fact, when Embers commits, it uses this default transaction. I can't use directly rollback on the store directly.
Instead of using store.rollback, you should have something like:
store.get('defaultTransaction').rollback()
or (if you are in a router event manager)
event.get('store.defaultTransaction').rollback()
You could also do a rollback on the model itself if it is in an "isDirty" state.
this.get('model').rollback();
Example
export default Ember.ObjectController.extend({
actions: {
cancelEditModel: function(){
this.get('model').rollback();
this.transitionToRoute('...');
return false;
}
}
});