Jason Butera
Jason Butera

Reputation: 2440

Add Error to JQuery Unobtrusive Validation Summary Without a Key

I've got a form that is using unobtrusive JQuery validation along with a validation summary. It works great. However, this form does an Ajax POST which returns a JSON result. If the result == true, then I continue. However, if the JSON result returns an array of messages, I want to fire the form validation in order to update the fields. Errors are returned as follows:

{
    "errors": [ 
       { "key" : "NameFirst", "message": "This is the message" },
       { "key" : "NameLast", "message": "This is the message" } 
     ]
}

I parse the JSON result and call showErrors() like so:

for (var j = 0; j < response.errors.length; j++) {
    var key = response.errors[j].key;
    var error = {};
    error[key] = response.errors[j].message;
    $form.data('validator').showErrors(error);
}

This correctly highlights the fields, but it doesn't update the validation summary. How can I get that to update?

Also, sometimes the errors are generic and don't map to a specific property/field in the model. In that case, they are returned with null keys like:

{
     "errors": [ 
        { "key" : null, "message": "This is the message" },
        { "key" : null, "message": "This is the other message" }, 
        { "key" : "NameFirst", "message": "This is the message" },
        { "key" : "NameLast", "message": "This is the message" } 
      ]
 }

I can't call showErrors on those because they don't map to a field identifier. Once I'm told how to update the summary, I sure I can append items to the list for the generic messages, but I'm open to other suggestions. Thanks!

UPDATE

Here is what I ended up doing that seems to work quite well. I have to build the summary manually in addition to calling showErrors on the valid keyed errors:

var $summary = $form.find("[data-valmsg-summary=true]")
                    .addClass("validation-summary-errors")
                    .removeClass("validation-summary-valid");
var $ul = $summary.find("ul").empty();

var error = {};
$.each(response.errors, function () {
    if (this.key)
        error[this.key] = this.message;
    $("<li />").html(this.message).appendTo($ul);
});
$form.validate().showErrors(error);

I hope this helps others.

Upvotes: 14

Views: 12891

Answers (5)

For my work i add the errors like this

var Frm =  "#SomeFrm"
, $validator = $(Frm).validate();


if (SomeNeedValid())
{
    $validator.errorList.push({"message":"fix error"});
    $(Frm).trigger('invalid-form.validate', validator);
}

Upvotes: 2

IdahoB
IdahoB

Reputation: 737

MVC 5 error clearing method (slightly different than above):

function resetValidation() {
    var form = $('#formName');
    var summary = form.find('[data-valmsg-summary=true]');
    var ul = summary.find('ul');
    ul.empty();
    summary.removeClass('validation-summary-errors').addClass('validation-summary-valid');
}

Enjoy!

Upvotes: 0

Sumguy
Sumguy

Reputation: 9

    if (!formValidator) {
        formValidator = $form.validate({}); // Get existing jquery validate object
    }

    // get existing summary errors from jQuery validate
    $.each(formValidator.errorList, function (index, errorListItem) {
        errorList.push(errorListItem.message);
    });

    // add our own errors
    if (testForErrorCondidtionA()) {
        errorList.push("Please fix error condition A!");
    }

    //unobtrusiveValidation should do the ul/summary dirty work.
    $form.trigger('invalid-form.validate', formValidator);

Upvotes: 0

Joseph King
Joseph King

Reputation: 5219

I needed to add my own custom error messages to the summary list. After a day or so perusing the jQuery validate and unobtrusive validation source code here is the solution I ended up using.

First I declared my form

@using (Html.BeginForm(null, null, FormMethod.Post, new {id = "formA"}))
{
    @Html.ValidationSummary()
           .....
           .....

Setting the id is important as I use this id in the javascript code to retrieve the form object.

I used the following code to update the summary error list on submit

$(function () {
    var formValidator,
        $form = $("#formA");

    // add handler to the forms submit action
    $form.submit(function () {
        if (!formValidator) {
            formValidator = $form.validate({}); // Get existing jquery validate object
        }

        var errorList = [];

        // get existing summary errors from jQuery validate
        $.each(formValidator.errorList, function (index, errorListItem) {
            errorList.push(errorListItem.message);
        });

        // add our own errors
        if (testForErrorCondidtionA()) {
            errorList.push("Please fix error condition A!");
        }

        if (testForErrorCondidtionB()) {
            errorList.push("Please fix error condition B!");
        }

        // No errors, do nothing
        if (0 === errorList.length) {
            return true; // allow submit
        }

        // find summary div
        var $summary = $form.find("[data-valmsg-summary=true]");

        // find the unordered list
        var $ul = $summary.find("ul");

        // Clear existing errors from DOM by removing all element from the list
        $ul.empty();

        // Add all errors to the list
        $.each(errorList, function (index, message) {
            $("<li />").html(message).appendTo($ul);
        });

        // Add the appropriate class to the summary div
        $summary.removeClass("validation-summary-valid")
            .addClass("validation-summary-errors");

        return false; // Block the submit
    });
});

This submit handler is always called after the unobtrusive handler, which means the summary error list we retrieve from jQuery validate will always be up to date.

Hope this answer helps as unobtrusive validation can get hairy once you veer away form the standard case(s).

Upvotes: 3

labroo
labroo

Reputation: 2961

I ran into the same problem and could not figure out a cleaner way. This is what I am thinking of doing

in place of this

for (var j = 0; j < response.errors.length; j++) {
    var key = response.errors[j].key;
    var error = {};
    error[key] = response.errors[j].message;
    $form.data('validator').showErrors(error);
}

Put this,

        var error = {}, keyLess = 0;

        for (var j = 0; j < response.errors.length; j++) {
            var key = response.errors[j].key;
            error[key || keyLess++] = response.errors[j].message;
        }

        $form.validate().showErrors(error);

        var container = $form.find("[data-valmsg-summary=true]"), 
            list = container.find("ul");

        if (list && list.length) {
            list.empty();
            container
              .addClass("validation-summary-errors")
              .removeClass("validation-summary-valid");

            $.each(error, function(k,m) {
                $("<li />").html(m).appendTo(list);
            });
        }

This is basically what jQuery.validate.unobtrusive does

What do you think?

Upvotes: 0

Related Questions