views:

835

answers:

1

I have been looking at many ASP.Net MVC client side validation ideas including xVal. This doesn't provide a ValidationSummary at the moment so I chose to do an AJAX post which loops through ModelState errors and update a DIV with the error messages on a successful AJAX post.

The problem with this is your ValidationMessage * next to the fields won't get populated. I have come up with an alternative idea which I haven't yet tested as I don't know the full syntax to get it working yet but thought I'd see what you guys thought.

One issue I think may be an issue is that when you post to your Edit/Create Action method in the controller and you want to return a JSON object, I'm not sure that is legal as JSON is used for GET actions only.

If you think its a good idea and are wanting to help please leave an answer and any code snippets to get this working. If you think its a hair brained scheme and can be done better please let me know how.

Controller:

if (!ModelState.IsValid)
{
            var err = ModelState.Where(f => f.Value.Errors.Count > 0);    
            if (Request.IsAjaxRequest())
            {
                   return this.Json(err);
            }
            else
            {
                  return View(PostedItem); 
            }
}

View:

    $(function() {



    $('#createForm').ajaxForm({
        success:fillSummary
    });

    //click events
    $('#btnSave').click( function(){
        $('#createForm').submit();
    });

    function fillSummary(data) 
    {
       //Loop through the modelstate errors returned
        $.each(data)
       {
            //Append Summary DIV with error message
            //Look for span with the ModelState key name and set it to visible
       }           
    }



    <div id="summary">
       <%= Html.ValidationSummary("Create was unsuccessful. Please correct the errors and try again.")%>
    </div>
    <form action="<%=Url.Action("Create") %>" method="post" id="createForm">

        <fieldset>
            <div>
                 <label for="Title">Title:</label>
                <%= Html.TextBox("Title",Model.Title) %>
                <%= Html.ValidationMessage("Title", "*") %>
                <span id="val_Title" style="display:none">*</span>              
            </div>
   </form>
   <input type="button" value="Save" id="btnSave" />
+1  A: 

In my current ASP.NET MVC project I have a lot of POST actions that I use for AJAX and ran across the validation issue too. What I did was create a wrapper object that gets returned from each of these actions which looks something like this...

public class JsonWrapper
{
   public object Data { get; set; }
   public bool IsError { get; set; }
   public string Message { get; set; }
}

If the validation in the action doesn't have any kind of errors, I place whatever data I want to return in the Data property. However, if there's any kind of validation error or other exception, I set the IsError flag to true and set an error message in the Message property. Then at the end of the action, I serialize the object to JSON and return it, (yes you can do this from a POST action)...

return Json(myJsonWrapper);

From the client side, in the onSuccess of my AJAX POST code, I check for errors, and take any actions neccessary like this... (Note, at this point in the code, the object that got returned from the server has already been deserialized into a JS object by jQuery)

function onSuccess(jsonWrapper) {
    if (!jsonWrapper.IsError) {
     var myDataFromAction = jsonWrapper.Data;
     //Do stuff with my data
    }
    else {
     MessageBox.ShowMessage(jsonWrapper.Message);
    }
}

This won't fit your scenario out of the box, but you could do something similar as a concept. Hope this at least gives you some ideas.

Lunchy
If there are no errors what's the MessageBox.ShowMessage - isn't that Windows Forms? If there are no errors server side I assume you continue in your Controller action and add data to the database? Do you only return the JSON when there are errors? Looks a good implementation though!
Jon
I implemented my own MessageBox client side control so I could easily show messages on the page, sorry for the confusion. :)And yea, if there aren't any errors, the controller action'll just do whatever it's meant to do, and I'll send back any interesting info to the client in the Data property, perhaps a record ID for a db insert for instance.I always pass a JSON JsonWrapper object back to the client when the client is expecting a response to an AJAX POST action. This allows a common API on the client side.Note, any object can be passed back in "Data", which allows great flexibility.
Lunchy
I have started to implement it but I am having issues with the JSON. When I try and append the data to the DIV it doesn't do anything. I have put an alert in and the data is coming back in the right format so I'm not sure. This is what I have: function showJSON(errors) { $("#summary").empty(); $.each(errors, function(i, error){ $("#summary").append(error.Text); }); }
Jon
Well, without seeing your serverside and clientside code it's tough to help with this one. I'd recommend using a javascript debugger to to inspect the object you get back from the server and attack it from that angle. Also, a DOM inspector like firebug or IE8's dev tools may help you to see what your javascript is doing to the page and thus get a clue as to what's wrong.
Lunchy
No worries, the AJAX post was not set to return JSON data. I have managed to get it all working by returning ModelState Key names and the error collection. I then loop through the errors on the OnSuccess event and put it in a validation summary div and also look for spans next to the fields and set them visible. All kinds of cool I think but with the lack of replies I guess no-one else thinks so! Thanks
Jon
Awesome! Glad you got something you're happy with. :-D
Lunchy
@Jon - any chance you could post code for the final solution?
jlembke