I have a form displayed in a jquery ui dialog. I load the form with ajax and I submit the form using ajax.
I now have validation that checks that a field is unique and that can only happen server-side.
So in my Controller I add any validation errors to ModelState:
public ActionResult CreateOrEdit(Property p)
{
_Uow.PropertyRepository.InsertOrUpdate(p);
//My unit of work has a method that returns any data layer validation errors
foreach (var error in _Uow.GetValidationErrors())
ModelState.AddModelError(error.Key, error.Value);
if (ModelState.IsValid)
_Uow.Save();
return GetCreateOrEditView(p, "Property");
}
EDIT I return the same view that is used in the get, so the behaviour is the same as if the field failed client side ie. the dialog contains a form and the validation error is displayed next to the field just like other errors.
Now, I don't want to close the dialog, and at the top of the dialog I have a validation legend created with this helper:
public static MvcHtmlString ValidationLegend(this HtmlHelper htmlHelper
, string message = "The form is invalid.")
{
string cssClass = htmlHelper.ViewData.ModelState.IsValid ?
"validation-summary-valid" : "validation-summary-errors";
var tagBuilder = new TagBuilder("div");
tagBuilder.Attributes.Add("id", "validation-legend");
tagBuilder.Attributes.Add("data-valmsg-summary", "true");
tagBuilder.SetInnerText(message);
tagBuilder.AddCssClass(cssClass);
return new MvcHtmlString(tagBuilder.ToString());
}
So this helper will display a legend with this html if there is a server error:
<div class="validation-summary-errors" data-valmsg-summary="true"
id="validation-legend">The form is invalid.</div>
So it's like a validation summary without all the extra messages - and I use the presence of the summary in my javascript to stop the dialog from closing.
I'd like to two things to happen: 1. When the user changes the field with the server-side error message, the validation error next to the field should clear (whatever it is changed to since I cannot check it server-side) 2. The validation legend should show when any validation fails and should hide when all invalid fields are cleared.
Currently the legend only displays for server validation errors and both the legend and the field error remain on screen until the submit button is clicked - which is inconsistent with the client-side validation.
Are there other data attributes that I can add to make this happen as part of the unobtrusive validation? Or is there another solution?
Here is my javascript:
function submitDialogForm(successCallback) {
var $dialog = $(this);
var $form = $dialog.find("form").filter(':visible:first');
if ($form.find("input:first").length > 0) {
if ($form.updateValidation().valid()) {
var $target = getTarget($dialog);
$form.ajaxSubmit({
target: $target,
success: function () {
$target.find(".fadein").show();
//Check if server side validation has failed before closing
$form = $dialog.find("form").filter(':visible:first');
if ($form.find("#validation-legend.validation-summary-errors").length > 0) {
return;
}
if (successCallback && typeof (successCallback) === "function") {
successCallback();
}
else {
$dialog.dialog("close");
}
}
});
}
}
else {
$dialog.dialog("close");
}
}
Included for completeness - code for validating form after it's been loaded using Ajax. Based on this answer: Update unobtrusive validation after ajax call
//jQuery plugin for updating unobtrusive validation when forms are loaded using Ajax
(function ($) {
$.fn.updateValidation = function () {
//If the form has been loaded via ajax, then we have to update the
//unobtrusive validation
var $this = $(this);
var form = $this.closest("form")
.removeData("validator")
.removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse(form);
return $this;
};
})(jQuery);