1

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);
Community
  • 1
  • 1
Colin
  • 22,328
  • 17
  • 103
  • 197
  • Are you actually sending a 500 (or similar) error code to the client? Is your `success` callback being triggered? – Justin Morgan - On strike Sep 18 '13 at 16:59
  • @JustinMorgan I don't send an error code. I return a partial view containing the original form, the div with the validation-summary-errors class and I put the validation error in ModelState. The presence of the div indicates that validation failed, success callback should not be called and the dialog should not be closed. All that works, but I'd like to get the validation to behave in a similar way to client-side validation after that – Colin Sep 18 '13 at 20:14

1 Answers1

0

I'm not really sure I understand your two goals:

  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.

However, as long as your server-side action is actually returning a server error code (presumably an HTTP 500 Internal Server Error message), what you want to do is add an error callback to your $.ajax call, just as you've done with the success callback. You could also use ajaxError to attach an error handler for all the page's AJAX activity.

If you're trying to clear existing validation errors (question 1 sounds like you're trying to do this), you want the reset or resetForm methods:

$form.ajaxSubmit({
        target: $target,
        success: function () {
            //...
        },
        error: function() {
            $form.validate().resetForm();
        }
    });

This is just a rough guess at the code you need, but hopefully you can extrapolate it from here. If you explain a little more what you want to do, I'll try to be more specific.

Justin Morgan - On strike
  • 30,035
  • 12
  • 80
  • 104
  • I think the Ajax is clouding the issue, the form is rendered correctly. I add an error to the ModelState and MVC renders the correct attributes to display a field validation error using unobtrusive JavaScript. I guess that if you add a "required" annotation to a property, then MVC renders the attributes to the input that ensure that when that input is changed to a valid value, the message is hidden. But we don't have a "validated on server" annotation to add here so MVC doesn't render the necessary attributes and that means the message stays until you resubmit – Colin Sep 18 '13 at 20:49