Reputation: 1013
I have a rails app serving json to an ember frontend.
I am trying to display validation errors from on a form on the client.
Rails is returning this json:
{"errors":{"hometown":["is too long (maximum is 64 characters)"]}}
In my handlebars template for the current route I am attempting to iterate through the errors but I don't get any output for the errors section:
<div class="form-group">
<label>Hometown</label>
{{#each errors.hometown}}
{{this}}
{{/each}}
{{input type="text" class="form-control" valueBinding="effectiveUser.hometown" disabled=entryNotAllowed size="50"}}
</div>
I also updated my RESTadapter based on this blog: https://marcqualie.com/2014/04/model-errors-in-emberjs to include:
ajaxError: function(jqXHR) {
var error = this._super(jqXHR);
if (jqXHR && jqXHR.status === 422) {
var jsonErrors = Ember.$.parseJSON(jqXHR.responseText)["errors"];
return new DS.InvalidError(jsonErrors);
} else {
return error;
}
}
I still really dont understand the context of what this errors object is and why my view has access to it that I but several different sources seem to say this setup should work. Any insight would be appreciated.
Upvotes: 4
Views: 2813
Reputation: 874
Well as far as i understand ember it's normal this isn't working :
To save your model in your controller/route/view you are performing a save()
operation which returns a promise. If a promise is rejected
a function to handle this rejection can be executed with a reason
as a parameter. In your case the DS.InvalidError
object will become this reason
.
myModel.save().then(function(value){
//success
},function(reason){
//fail
});
so in your case (but depends where you are handeling action i will supose in controller) something like that should do the trick;
actions: {
submitForm : function(){
this.set("errors",null);
var ctx=this;
myModel.save().then( function(){
//display a succes msg ?
}, function(errors){
ctx.set("errors",errors);
});
}
}
Upvotes: 2
Reputation: 6366
Recent Ember Data Beta's since 1.0 Beta 12 pass the errors to the model. The store processes InvalidError
results for you and places the errors on the model.
I submitted a PR #2392 which has been merged allowing your model serializers the opportunity to extract errors from the error payload prior to being set on the model. The default implementation ensures that error payload keys are now correctly mapped to attribute keys whereas previously this was not the case.
Ember Data will still only apply errors to the model which have a corresponding attribute defined. This has been a source of frustration since often there are errors (eg "base") that apply to the model as a whole. This is covered in the outstanding issue #1984, with the following workaround until it is merged.
DS.Model.reopen({
adapterDidInvalidate: function(errors) {
var recordErrors = this.get('errors');
for (var key in errors) {
if (!errors.hasOwnProperty(key)) continue;
recordErrors.add(key, errors[key]);
}
}
});
Your template code should also follow the example in DS.Errors:
{{#each message in errors.messages}}
<div class="error">
{{message}}
</div>
{{/each}}
You may wish to use the errorsFor method to target a specific attribute.
You may also want to use a helper or component that extracts an attribute specific model error and marks it up appropriately. Some example code on how to do this is available in the ember-forms add-on.
I also just discovered a tutorial on Ember Data server side error handling which may be useful, just ignore the RESTAdapter bit since it's out of date now.
Upvotes: 3
Reputation: 404
I have implemented the ajaxError
method like show below.
App.ApplicationAdapter = DS.RESTAdapter.extend({
ajaxError: function(jqXHR){
error = this._super(jqXHR);
if (jqXHR.status == 422) {
response = Ember.$.parseJSON(jqXHR.responseText);
errors = {};
if (typeof response.errors !== 'undefined') {
jsonErrors = response.errors;
Ember.keys(jsonErrors).forEach(function(key) {
errors[Ember.String.camelize(key)] = jsonErrors[key]
});
}
if (typeof response.message !== 'undefined') {
errors['Message'] = response.message;
}
return new DS.InvalidError(errors)
} else {
return error
}
}
});
Using the previous code I'm able to get errors
on my template.
{{#each message in errors.messages}}
<strong>{{message}}</strong><br />
{{/each}}
Upvotes: 0