I have a question regarding Ember-Data and creating a new Record. I have a route and a template for creating a new record that looks something like this:
The created record, as my model, binds to my template and it’s easy to create the user when they click the submit button, and easy to delete the record when they click the cancel button. But if they navigate away from the new user template through some other link, (like the page’s navbar), I find that I have the dirty record in the local ember-data store. The record shows up on the display page. I do not want this. I tried solving my problem by replacing the model function with this:
But this generates the following runtime error message:
Error while processing route: users.new You should not call create
on a model. Instead, call store.createRecord with the attributes you
would like to set. Error: You should not call create on a model.
Instead, call store.createRecord with the attributes you would like
to set.
I’m sort of at a loss on how to proceed. What is the best way to do two-way binding in a CRUD function, so that if the user navigates away via a link or back button before submitting, it doesn’t save the record to the data store?
App.UsersNewRoute = Em.Route.extend({
model: function() {
return this.store.createRecord('user');
},
resetController: function(controller) {
var user = controller.get('model');
if (user.get('isDirty')) user.rollback();
}
})
The idea is using resetController to rollback model changes when route is exiting or the model is replaced. There are other solutions which use deactivate but I prefer resetController. No matter the user is a new record or an existing record, rollback will do the right thing for you.
You can also extract this logic to a mixin and mix into all your CRUD routes.
As of Ember-Data 2.1, the above solution is not accurate. Here’s an update, for an route called players/new, which is used to create new instances of the model player:
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return this.store.createRecord('player');
},
actions: {
save() {
const record = this.modelFor('players.new');
record.save()
.then(() => {
this.transitionTo('root.show');
})
.catch(error => {
console.error("Error saving player", error);
});
},
willTransition() {
const record = this.modelFor('players.new');
if (record.get('isNew')) {
return record.destroyRecord();
}
},
},
});
Points of note:
rollback doesn’t exist anymore. Here I destroy the record with destroyRecord
isDirty is also gone. I replaced it with isNew in this example
resetController doesn’t seem to wait for the promise returned by destroyRecord, meaning the record will still exist when the new route is loaded. Fortunately, willTransition does wait for you
Unfortunately, 1 and 2 only make sense when creating records, not updating them. At the moment my app only creates, so I haven’t had to dig into that problem just yet.
I’d love to hear suggestions on how this can be improved
As mentioned above, isDirty doesn’t exist anymore. Instead, I just rollbackAttributes() without asking. If we saved earlier, now there won’t be any changes to roll back.