I posted a while ago on asynchronous saves in MVC 3. One thing to note that after the new content is loaded into the browser, client side validation is broken. The reason being is that content is only parsed once by unobtrusive jQuery validation. To fix this issue I would need to force the validator to parse the content again. Here is what my JavaScript to submit the form would look like now (changes from previous post are in bold)
@if (false)
{ <script src="../../Scripts/jquery-1.5.1-vsdoc.js" type="text/javascript"></script>}
@model MvcEFCodeFirst.Data.Attendee
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>
@ViewBag.Title</h2>
<div id="formDiv">
@{Html.RenderPartial("AttendeePartial", Model);}
</div>
<div>
<button id="saveNewAttendee">
@ViewBag.ButtonText
</button>
</div>
<div>
@Html.ActionLink("Back to List", "Index")
</div>
<script type="text/javascript">
$().ready(function () {
$(‘#saveNewAttendee’).click(function () {
if (!$(‘form’).valid()) {
return false;
}
$.blockUI({ message: ‘<h1>Updating…</h1>’ });
$.ajax({
type: "POST",
url: "./CreateUpdateAjax",
data: $(‘form’).first().serialize(),
success: function (data, status, xhr) {
$(‘#formDiv’).html(data);
if ($(‘#AttendeeID’).val() != undefined) {
$(‘#saveNewAttendee’).html(‘Save’);
};
$.unblockUI();
jQuery.validator.unobtrusive.parse(‘form’);
},
error: function (xhr, status, error) {
$.unblockUI();
alert("error");
}
});
})
})
</script>
I also would like to spend a bit of time on custom client side validation that is not built based on attributes in POCO classes of Entity Framework. There are two types of this kind of validation. One that can be done completely on client side and another that requires a database access or some other information from the server. I am going to chat about latter first.
I can accomplish this task via Remote attribute. All I need to do is decorate a property with this attribute to force validation to invoke a controller method when data changes for that property. This is still accomplished via unobtrusive JavaScript validation. What you need to do is decorate a property you are validating with Remote attribute and specify what method on controller needs to be invoked as well as additional fields to pass to the method and error message to show. The method just needs to return true or false, where or not the validation passes. Here is an example of the property decorated with the attributes.
[Remote(
"DuplicateEmail",
"Attendee",
AdditionalFields = "AttendeeID",
ErrorMessageResourceName = "DuplicateEmail",
ErrorMessageResourceType = typeof(Resource))]
public string Email { get; set; }
What I am trying to do above is validate to see if the email is a duplicate. I am passing Attendee ID to the method as well to make sure email is not a duplicate, but I have to filter our current record. Word attendee is the name of the controller, of course you have to omit word controller out of the call, since this is how MVC is building ajax call. Here is what my controller method looks like
public JsonResult DuplicateEmail(string email, int? attendeeID)
{
int id = attendeeID.HasValue ? attendeeID.Value : 0;
return Json(!db.Select<Attendee>()
.Where(one => one.Email == email && one.AttendeeID != id).Any(),
JsonRequestBehavior.AllowGet);
}
The query using Entity Framework Code First is very simple and does not need much explanation. What I notice is that my parameters are matched based on names and automatically parsed for me. Attendee ID is nullable because for brand new attendee entry is not populated yet. Here is code from my view to show why.
@if (Model.AttendeeID > 0)
{
@Html.HiddenFor(model => model.AttendeeID)
}
I am only dumping ID for existing rows, i.e. for editing, not new attendee creation. I also use this fact to conditionally edit or create new row. You can see that in the JavaScript method on top if this post. All this data gets translated into unobtrusive JavaScript validation calls on the client. In the next post I will talk about the other side of custom client validation based on IClientValidatable interface.
Thanks.
Maybe you are replacing HTML? In that case you need to call jQuery.validator.unobtrusive.parse(‘form’); after you update html.