I'm using ember(+data) and have built a simple signup form, but I'm having trouble getting the form (and ember-data transaction) to work properly after a server-side validation error.
I'm following https://github.com/dgeb/ember_data_example as a guide for how to use transactions, and it mostly works for the Happy Path, but after a server-side validation error, I can't get ember-data to resubmit the API request when I click Submit.
I did some digging around, and I think I'm missing some step related to resetting the transaction after the model becomes invalid or something like that...
Github and App
You can try the app and reproduce the problem at http://emb.herokuapp.com/
You can also examine the full source code at https://github.com/justinfaulkner/ember-data-resubmit
Repro
You can trigger a fake server-side error by completing the form in my app using an e-mail address at @example.com. The Rails API will respond 422 and an errors object keyed to the username/email field.
The field should be highlighted in red with an error -- edit the email address to something that should be valid, and click Submit again. With developer tools open in chrome, I don't see ember-data sending an http request with the click (but a console.log in the controller indicates that the click is indeed being received).
What should happen
After modifying the field with the error, ember-data (I think) changes the model's from invalid
to uncommitted
so that it gets submitted the next time commit
is called. When I click Submit, ember-data should send the HTTP request to my api, and ember should transition to the "Congrats!" page.
Instead, however, the form just sits there. No http request. No transition to "Congrats!".
Here's a screenshot after I clicked Submit a few (18) times after having updated the inputs:
Snippets
Here are some snippets of my ember app:
IndexRoute
My route, which uses startEditing
like ember_data_example does:
App.IndexRoute = Ember.Route.extend({
model: function() {
return null;
},
setupController: function(controller) {
controller.startEditing();
},
deactivate: function() {
this.controllerFor('index').stopEditing();
}
});
IndexController
My IndexController
is modeled after ember_data_example's ContactsNewController
App.IndexController = Ember.ObjectController.extend({
startEditing: function() {
this.transaction = this.get('store').transaction();
this.set('content', this.transaction.createRecord(App.User));
},
submit: function(user){
console.log("submitting!");
this.transaction.commit();
this.transaction = null;
},
_transitionOnSuccess: function(stuff) {
if (this.get('content.id') && this.get('content.id').length > 0) {
console.log("_transitionOnSuccess");
this.transitionToRoute('success');
}
}.observes('content.id'),
stopEditing: function() {
if (this.transaction) {
this.transaction.rollback();
this.transaction = null;
}
}
});
User
Here's my model. I'm using ember-validations.
App.User = DS.Model.extend(Ember.Validations.Mixin);
App.User.reopen({
username: DS.attr('string'),
password: DS.attr('string'),
profile: DS.belongsTo('App.Profile'),
validations: {
username: {
presence: true
},
password: {
presence: true,
length: { minimum: 6 }
}
}
});
index.hbs
And here's the form from my handlebars template. I'm using ember-easyForm.
{{#formFor controller}}
<div class="row">
<div class="large-12 columns">
{{input username placeholder="Email address"}}
</div>
</div>
<div class="row">
<div class="large-12 columns">
{{input password placeholder="Password"}}
</div>
</div>
{{submit "Sign Up" class="button"}}
{{/formFor}}
In case the library authors see this post, I have made a couple local modifications to the app's copy of ember-easyForm and ember-validations in this commit: https://github.com/justinfaulkner/dockyard-example/commit/f618b0e4fb72314d56bb3a9d95e1325925ba6ad0 . I don't think my changes are causing my problem, though.
becameInvalid and rollback?
I did run across a similar-looking question here: Ember Data and dirty records but when I added a User.becameInvalid
to rollback the transaction, this caused the form to empty when trying to re-submit (and still no success having ember-data resubmit the http request).
Thanks!
I'm sure I'm following ember_data_example
poorly (or failing to extend it to my use-case) or am making some simple mistake somewhere...
Thanks in advance.
Edit Apr 5
So far, I can find at least two main problems:
this.transaction = null;
Do I need this? What should I do instead?- I tried removing
this.transaction = null;
and ember-data tries to actually commit now (but still won't submit the ajax request). Now, when I type in the invalid field, I can see ember-data try to update the record back touncommitted
/created
... but it does it in a different transaction.
I pushed up a no-null
branch to the repo that has some console.log
s in ember-data that prints out what the transaction ID is... here's a snapshot of my console:
recordBecameDirty
is called when I type in the field. Ember-data updates the record to be ready to be committable again. But, it's doing it in some other transaction (458)
But my submit button is tied to the original transaction (316), and there's no records ready to commit in that transaction.... hmm....
this.transaction = null;
I would think this would prevent any subsequent requests from going through (though, I would also expect the console to show an error about calling commit on null). – Adam