What's the recommended way to display errors from JavaScript (jQuery) in ASP.NET MVC 3 views?
I submit a form to my ASP.NET MVC 3 server through a JavaScript handler (I use jQuery), and receive error responses from the server in another JavaScript handler. What I'm wondering is how I should display error messages, resulting from the form submission, in the view? I would prefer using some standard ASP.NET MVC 3 idiom/construct.
EDIT
开发者_开发问答Note that I want to display error messages from the server, received in a JavaScript error handler function.
You can go the pure MVC way: http://www.asp.net/mvc/tutorials/creating-a-mvc-3-application-with-razor-and-unobtrusive-javascript
Scroll down to "Enabling Client-Side Validation."
In your View you'll have code that looks like this:
@Html.TextBoxFor(model => model.UserName)
@Html.ValidationMessageFor(model => model.UserName)
UPDATE
Seems OP is interested in custom messaging. There isn't any MVC construct for this sort of custom messaging. Your best bet is to just create your own messaging area and write messages to it in your callback function. Shouldn't be too complicated!
$.ajax(..., function(data) {
$('#errors').append('<p>' + data + '</p>');
});
Assuming you are using jQuery validate that comes with MVC solution templates, in your javascript handler you will have to add errors to the validator. There is a showErrors
method on validator.
On the client side:
var formSubmitCallback = function(result){
var validator = $(this).data('validator');
if(!result.IsValid && validator)
validator.showErrors(result.Errors); // uses jquery validator to highlight the fields
// process the rest of the result here
// if result.Action == ActionTypes.Redirect
// location.href = result.Url
// etc
}
Now I had to standardize the result object from the server to return a json object formatted with { "FieleName": "Error Message" }
. I built a few Controller
and ViewModel
extension on the server side to accomplish that.
On the server side:
public ActionResult SomeAction(Model someModel){
if(ModelState.IsValid)
// save
else
// other stuff
// always return this.AjaxSubmit.
// Extension function will add Errors, and IsValid to the response data
return this.AjaxSubmit(new ClientAction{
Action = ClientActionType.Redirect,
Url = "/Some/Redirect/Route"
});
}
Note: looking back on this now I did write a bit of custom code to make it work. I will eventually add the client and server code, together with examples on github. But this is the general idea.
The server classes and extension you will need are below
// GetAllErrors is a ModelState extension to format Model errors for Json response
public static Dictionary<string, string> GetAllErrors(this ModelStateDictionary modelState)
{
var query = (from state in modelState
where state.Value.Errors.Count > 0
group state by state.Key into g
select new
{
FieldName = g.Key,
FieldErrors = g.Select(prop => prop.Value.Errors).First().Select(prop => prop.ErrorMessage).ToList()
});
return query.ToDictionary(k => k.FieldName, v => string.Join("<br/>", v.FieldErrors));
}
// Controller result extension to return from actions
public static JsonResult AjaxSubmit(this Controller controller, ClientAction action)
{
if (controller == null) return new JsonResult { Data = action };
var result = new AjaxSubmitResult
{
Errors = controller.ModelState.GetAllErrors(),
IsValid = controller.ModelState.IsValid,
ClientAction = action
};
return new JsonResult{ Data = result };
}
// Action to perform on the client after a successful, valid response
public class ClientAction
{
public ClientActionType Action { get; set; }
public string Url { get; set; }
public string Function { get; set; }
public object Data { get; set; }
public Dictionary<string, string> Updatables { get; set; }
}
public enum ClientActionType
{
Redirect,
Ajax,
Function,
Modal,
Message,
FunctionAndMessage
}
The server should respond with a standardized message. That message could contain a complete error message (HTML) which you can then display in an empty div that is part of your _Layout
page:
function(response) {
if(response.Status === "error") {
$("#errorContainer").html(response.ErrorHtml);
} else {
// the success handler
}
}
The upside is that you can perform a rather standardized error message rendering on the server. Of course you could also display these as js popups / modal dialogs, etc.
The formatting of the error message is done via CSS that can be applied quite generically to #errorContainer
and its contents.
You might want to argue that it is cleaner to respond with plain text from the server and add any html in the client via JS. That is possible, too, and probably works better with 'real' REST APIs. However, it does not allow to use formatted error messages (e.g. with links, etc.)
I answered something similar in the past on this for adding the error messages.
MVC Validation Summary manipulation with JS and Dynamic DOM elements
Since you want errors coming back from the server in what I'm assuming is your already known javascript method, simply add
var ul = $("#validationSummary ul"); ul.append("<li>Custom Error Message</li>")
The way I do it is:
Create base controller class and override the OnException handler
public abstract class MyBaseController : Controller
{
protected override void OnException(ExceptionContext filterContext)
{
if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
{
// add my own status code
Response.StatusCode = 550;
// write the error message to the response
Response.Write(filterContext.Exception.Message);
// mark the exception as handled
filterContext.ExceptionHandled = true;
}
base.OnException(filterContext);
}
}
On the client side on document ready I register global handler for ajax errors
$(document).ready(function(){
$.ajaxSetup({
error:function(x,e){
if(x.status==0){
alert('You are offline!!\n Please Check Your Network.');
}else if(x.status==404){
alert('Requested URL not found.');
}else if(x.status==550){ // <----- THIS IS MY CUSTOM ERROR CODE --------
alert(x.responseText);
}else if(x.status==500){
alert('Internel Server Error.');
}else if(e=='parsererror'){
alert('Error.\nParsing JSON Request failed.');
}else if(e=='timeout'){
alert('Request Time out.');
}else {
alert('Unknow Error.\n'+x.responseText);
}
}
});
});
You can of course tweak this methods to suite your needs. Hope this helps.
精彩评论