Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set $jQval.unobtrusive.options ErrorPlacement function correclty

What is the proper way to override the ErrorPlacement function in jquery.validate.unobtrusive?

Looking at the jquery.validate.unobtrusive.js script it appears that the developers intention would allow you to apply your own ErrorPlacement function by setting $jQval.unobtrusive.options.

In the validationInfo(form) function that defines the errorPlacement function we see a call to execInContext("errorPlacement", arguments).

It would seem that if we create a errorPlacement function under $.validator.unobtrusive.options then this will be called.

   $.validator.unobtrusive.options = {
        errorPlacement: function () {
            console.log("hello");
        }
    };

The issue is that this must configured after jquery.validate.js and before jquery.validate.unobtrusive.js is referenced. Otherwise $jQval.unobtrusive.options is null and $form.data(data_validation, result) will not be set again.

    function validationInfo(form) {
    var $form = $(form),
        result = $form.data(data_validation),
        onResetProxy = $.proxy(onReset, form),
        defaultOptions = $jQval.unobtrusive.options || {},
        execInContext = function (name, args) {
            var func = defaultOptions[name];
            func && $.isFunction(func) && func.apply(form, args);
        }

    if (!result) {
        result = {
            options: {  // options structure passed to jQuery Validate's validate() method
                errorClass: defaultOptions.errorClass || "input-validation-error",
                errorElement: defaultOptions.errorElement || "span",
                errorPlacement: function () {
                    onError.apply(form, arguments);
                    execInContext("errorPlacement", arguments);
                },
                invalidHandler: function () {
                    onErrors.apply(form, arguments);
                    execInContext("invalidHandler", arguments);
                },
                messages: {},
                rules: {},
                success: function () {
                    onSuccess.apply(form, arguments);
                    execInContext("success", arguments);
                }
            },
            attachValidation: function () {
                $form
                    .off("reset." + data_validation, onResetProxy)
                    .on("reset." + data_validation, onResetProxy)
                    .validate(this.options);
            },
            validate: function () {  // a validation function that is called by unobtrusive Ajax
                $form.validate();
                return $form.valid();
            }
        };
        $form.data(data_validation, result);
    }

    return result;
}

The other way to get deal with this is to

  1. set the $.validator.unobtrusive.options error Placement Function

  2. remove the Unobtrusive Validation

  3. re apply the unobtrusive validation

    $.validator.unobtrusive.options = {
        errorPlacement: function () {
            console.log("errorPlacement");
        }
    };
    
    
    $("#form_selector").removeData("unobtrusiveValidation");
    
    // reapply the form's validator
    $.validator.unobtrusive.parse(document);
    

Or the other option would be to override the function call.

var validator = $("#form_selector").data('validator');
var originalFunction = validator.settings.errorPlacement;
validator.settings.errorPlacement = function(error,element) {
    console.log("errorPlacement");
    originalFunction(error, element);
};

Which is the proper way of implementing your own errorPlacement method?

like image 398
Adrian Halid Avatar asked Aug 18 '14 02:08

Adrian Halid


1 Answers

3 years late to answer, but turns out I needed exactly this today. It's possible the unobtrusive code has been fixed in that timeframe, but your example code worked just fine for me. I added this to one of my site scripts that was loaded after both jquery.validate.js and jquery.validate.unobtrusive.js:

$.validator.unobtrusive.options = {
    errorPlacement: function () {
        console.log("hello");
    }
};

It worked fine, but with one additional catch: this line has to be ran before document ready. The validationInfo method is called on document ready via this, from the bottom of jquery.validate.unobtrusive.js:

$(function () {
    $jQval.unobtrusive.parse(document);
}); 

parse ultimately calls validationInfo. The problem with the unobtrusive code is when validationInfo sets defaultOptions = $jQval.unobtrusive.options || {}. Clearly if you haven't defined the unobtrusive.options by this point, it'll stupidly set defaultOptions to a blank object and never check it again, regardless of what you do to $jQval.unobtrusive.options. If they just removed the || {} everything would work great, since it's just an object reference. Alas...


If you can't set the errorPlacement callback before your document is loaded, or you need to alter it dynamically, just add this one line in one of your scripts that loads after jquery.validate.js and jquery.validate.unobtrusive.js:

$.validator.unobtrusive.options = {};

That will cause defaultOptions to point to an object you can reference. Then, wherever you need, alter $.validator.unobtrusive.options as you'd expect. Just be careful not to overwrite the object since you wouldn't affect the object pointed to by defaultOptions if you did. ie, do this:

$.validator.unobtrusive.options.errorPlacement: function () {
    console.log("hello");
};
like image 62
Ber'Zophus Avatar answered Sep 21 '22 09:09

Ber'Zophus