Basically I'm having trouble showing modelstate errors returned from the controller (WebApi). Using MVC4,jQuery and knockout. Hopefully you can see what I am trying to achieve from the below - thanks in advance.
View:-
<div class="editor-field">
@Html.TextBoxFor(model => model.CostCode,
new
{
placeholder = "cost/budget code",
data_bind = "value: CostCode"
})
</div>
<div>
@Html.ValidationMessageFor(model => model.CostCode)
</div>
knockout viewmodel doing the post/submit:-
if (validator.valid())
{
console.log('is valid');
$.ajax({
url: '/api/Booking/CompleteBooking',
type: 'POST',
dataType: 'json',
data: ko.mapping.toJS(self),
error: function (jqXHR) {
extractErrors(jqXHR, validator);
},
success: function (data) {
console.log(data);
}
});
}
function extractErrors(jqXhr, validator)
{
var data = $.parseJSON(jqXhr.responseText),
errors = { };
$.each(data.ModelState, function (i, item) {
errors[i] = item;
});
console.log(errors);
validator.showErrors(errors);
}
Controller:-
[ModelValidationFilter]
public HttpResponseMessage CompleteBooking(AdditionalBookingInfoViewModel model)
{
return new HttpResponseMessage(HttpStatusCode.OK);
}
ActionFilterAttribute (note the modelstate being sent back)
public class ModelValidationFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (!actionContext.ModelState.IsValid)
{
actionContext.Response =
actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState);
}
}
}
Rendered markup:-
Firebug response:-
Now, I know the validator will try and find an element with the name 'model.CostCode' not just 'CostCode' as it appears in the markup, but I've tried setting the Id & name to 'model.CostCode' to match but it doesn't make any difference. I think there is a problem with my extractErrors function.
If I hardcode an error message the validator works ok
validator.showErrors({
"CostCode" : "Test test test!"
});
By the way, is this an acceptable way of showing server side validation messages or am I barking up the wrong tree with all this? Any pointers/comments very welcome thank you.
At a guess, as you haven't shown us the output from console.log(errors), you are producing an array of the error items, but in the working example, you just have a hashtable that is keyed on the field name.
{
0: { 'model.CostCode': ['Please enter a valid cost code.'] }
}
vs
{
"CostCode" : "Test test test!"
}
So your error message is an array, whereas the working example isn't. So you need to change your extractErrors method to parse the data, rather than just copying it over:
for(var key in data.ModelState)
{
errors[key.replace('model.', '')] = data.ModelState[key][0];
}
That's a little hacky, but it should get you on the right path!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With