Add Error to JQuery Unobtrusive Validation Summary Without a Key
Asked Answered
C

5

14

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.

Caylor answered 3/3, 2015 at 19:29 Comment(0)
A
3

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).

African answered 7/8, 2015 at 7:30 Comment(0)
A
2

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);
}
Autoplasty answered 10/1, 2020 at 2:37 Comment(0)
R
0

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?

Respond answered 3/3, 2015 at 23:49 Comment(1)
That is almost exactly what I ended up doing. However, showErrors() throws an exception when there is a key that doesn't map to a field name. It seems to pass around a null element that it ends up trying to call highlight() on, resulting in a "Cannot read property 'type' of undefined" error. So I can't use your keyLess incrementor. I'm going to update my post with something similar. I basically add all errors to the UL, but only add valid key errors to the error object.Caylor
E
0
    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);
Equuleus answered 8/1, 2016 at 20:41 Comment(2)
Welcome to Stack Overflow! Please add some explanation of why this code helps the OP. This will help provide an answer future viewers can learn from. See How to Answer for more information.Apophyllite
@Equuleus Hello I have tried your solution but I got errorList on second submit button. Please see my question here #39834227 so you can understand it better.Seaquake
H
0

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!

Hepsibah answered 14/7, 2017 at 21:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.