Integrating qTip with MVC3 and jQuery Validation (errorPlacement)
Asked Answered
E

5

13

I am working on a proyect with MVC3 and I am trying to integrate qTip2 with jQuery validation in order to show errors as floating tips. The problem I am having is that apparently calling errorPlacement on form validation is not doing anything, guess it has something to do with the way MVC handles it.

Basically, what I want to do is use the integrated validation between MVC3 and jQuery (annotations) but also integrated with qTip to change how the error msg is shown.

I have searched all over and the best I could find was someone suggesting modifying the jquery.validate.unobtrusive.js - onError function, but I checked it out and had no idea how to modify it properly, plus would prefer a solution that did not require me to alter existing scripts.

Thank you for your help.

What I have so far:

My Model:

public class User
{
    [Required]
    public string Id { get; set; }

        [Required]
    [DataType(DataType.EmailAddress)]
    public string Email { get; set; }

    public string FirstName { get; set; }

    public string SecondName { get; set; }

    public string LastName { get; set; }
}

My javascript in my view:

$('#Form').validate({
    errorClass: "errormessage",
    errorClass: 'error',
    validClass: 'valid',
    errorPlacement: function (error, element) {
        // Set positioning based on the elements position in the form
        var elem = $(element),
            corners = ['left center', 'right center'],
            flipIt = elem.parents('span.right').length > 0;

        // Check we have a valid error message
        if (true) {
            // Apply the tooltip only if it isn't valid
            elem.filter(':not(.valid)').qtip({
                overwrite: false,
                content: error,
                position: {
                    my: corners[flipIt ? 0 : 1],
                    at: corners[flipIt ? 1 : 0],
                    viewport: $(window)
                },
                show: {
                    event: false,
                    ready: true
                },
                hide: false,
                style: {
                    classes: 'ui-tooltip-red' // Make it red... the classic error colour!
                }
            })

            // If we have a tooltip on this element already, just update its content
            .qtip('option', 'content.text', error);
        }

        // If the error is empty, remove the qTip
        else { elem.qtip('destroy'); }
    },
    success: $.noop // Odd workaround for errorPlacement not firing!
})

$('#Form').submit(function () {
    if (!$(this).valid())
        return false;

    $.ajax({
        url: this.action,
        type: this.method,
        data: $(this).serialize(),
        beforeSend: function () {
        },
        success: function (result) {
        },
        error: function (result) {
        }
    });
    return false;
});
Epizoon answered 23/7, 2011 at 17:19 Comment(0)
E
11

Alternate Solution

My first solution worked, but also caused some unexpected behaivior in certain situation. I fixed by including the errorPlacement code on the onError function in the same js file:

function onError(error, inputElement) {  // 'this' is the form element
    var container = $(this).find("[data-valmsg-for='" + inputElement[0].name + "']"),
        replace = $.parseJSON(container.attr("data-valmsg-replace")) !== false;

    container.removeClass("field-validation-valid").addClass("field-validation-error");
    error.data("unobtrusiveContainer", container);

    if (replace) {
        container.empty();
        error.removeClass("input-validation-error").appendTo(container);
    }
    else {
        error.hide();
    }

    var element = inputElement;
    // Set positioning based on the elements position in the form
    var elem = $(element),
                        corners = ['left center', 'right center'],
                        flipIt = elem.parents('span.right').length > 0;

    // Check we have a valid error message
    if (!error.is(':empty')) {
        // Apply the tooltip only if it isn't valid
        elem.filter(':not(.valid)').qtip({
            overwrite: false,
            content: error,
            position: {
                my: corners[flipIt ? 0 : 1],
                at: corners[flipIt ? 1 : 0],
                viewport: $(window)
            },
            show: {
                event: false,
                ready: true
            },
            hide: false,
            style: {
                classes: 'ui-tooltip-red' // Make it red... the classic error colour!
            }
        })

        // If we have a tooltip on this element already, just update its content
        .qtip('option', 'content.text', error);
    }

    // If the error is empty, remove the qTip
    else { elem.qtip('destroy'); }
}

And then you can submit a form, checking for validation this way:

$('#frm').submit(function () {
    if (!$(this).valid())
        return false;

    $.ajax({
        url: this.action,
        type: this.method,
        data: $(this).serialize(),
        beforeSend: function () {
        },
        success: function (result) {
        },
        error: function (result) {
        }
    });
    return false;
});
Epizoon answered 9/8, 2011 at 22:54 Comment(7)
The above solution solved the issue I mentioned as well. Thanks!Schluter
Any ideas on how to get the tip to display for server side validation messages that come back after a post to the server?Schluter
@Nick-Olsen - The qTip integration works with jQuery client side validation... To implement it for server side validation I guess you have to program it in a case by case basis. But I am not sure if there is a better way. I think this could be a question on its own. Post it so you can get help from the entire community...Epizoon
I figured out how to do it by the way. The solution can be found here #7017530Schluter
@Nick-Olsen - cool... I might be using that later on... thanks.Epizoon
hi, it works, but i notice that the original ValidationMessage label displays first, then your code hides it, then the qtip displays. it causes the page layout to re-render, seems like dancing/bumping. any idea how to solve it?Verdin
ok, i figured it out, just remove .appendTo(container) and it's all fine. thanks mate, your code rocks!Verdin
L
13

Great solution thanks, I've used this im my application.

...To further add, instead of modifying the jquery.validate.unobtrusive.min.js file directly I used the following to modify the default behaviour of unobtrusive validation.

$(document).ready(function () {

            var settngs = $.data($('form')[0], 'validator').settings;
            settngs.errorPlacement = function(error, inputElement) {
                // Modify error placement here
            };
});

Eagerly Performing ASP.NET MVC 3 Unobtrusive Client Side Validation

Levileviable answered 27/11, 2011 at 20:34 Comment(0)
E
11

Alternate Solution

My first solution worked, but also caused some unexpected behaivior in certain situation. I fixed by including the errorPlacement code on the onError function in the same js file:

function onError(error, inputElement) {  // 'this' is the form element
    var container = $(this).find("[data-valmsg-for='" + inputElement[0].name + "']"),
        replace = $.parseJSON(container.attr("data-valmsg-replace")) !== false;

    container.removeClass("field-validation-valid").addClass("field-validation-error");
    error.data("unobtrusiveContainer", container);

    if (replace) {
        container.empty();
        error.removeClass("input-validation-error").appendTo(container);
    }
    else {
        error.hide();
    }

    var element = inputElement;
    // Set positioning based on the elements position in the form
    var elem = $(element),
                        corners = ['left center', 'right center'],
                        flipIt = elem.parents('span.right').length > 0;

    // Check we have a valid error message
    if (!error.is(':empty')) {
        // Apply the tooltip only if it isn't valid
        elem.filter(':not(.valid)').qtip({
            overwrite: false,
            content: error,
            position: {
                my: corners[flipIt ? 0 : 1],
                at: corners[flipIt ? 1 : 0],
                viewport: $(window)
            },
            show: {
                event: false,
                ready: true
            },
            hide: false,
            style: {
                classes: 'ui-tooltip-red' // Make it red... the classic error colour!
            }
        })

        // If we have a tooltip on this element already, just update its content
        .qtip('option', 'content.text', error);
    }

    // If the error is empty, remove the qTip
    else { elem.qtip('destroy'); }
}

And then you can submit a form, checking for validation this way:

$('#frm').submit(function () {
    if (!$(this).valid())
        return false;

    $.ajax({
        url: this.action,
        type: this.method,
        data: $(this).serialize(),
        beforeSend: function () {
        },
        success: function (result) {
        },
        error: function (result) {
        }
    });
    return false;
});
Epizoon answered 9/8, 2011 at 22:54 Comment(7)
The above solution solved the issue I mentioned as well. Thanks!Schluter
Any ideas on how to get the tip to display for server side validation messages that come back after a post to the server?Schluter
@Nick-Olsen - The qTip integration works with jQuery client side validation... To implement it for server side validation I guess you have to program it in a case by case basis. But I am not sure if there is a better way. I think this could be a question on its own. Post it so you can get help from the entire community...Epizoon
I figured out how to do it by the way. The solution can be found here #7017530Schluter
@Nick-Olsen - cool... I might be using that later on... thanks.Epizoon
hi, it works, but i notice that the original ValidationMessage label displays first, then your code hides it, then the qtip displays. it causes the page layout to re-render, seems like dancing/bumping. any idea how to solve it?Verdin
ok, i figured it out, just remove .appendTo(container) and it's all fine. thanks mate, your code rocks!Verdin
D
5

My solution - can be used in separate .js file and if placed in master page, works for whole site.

$(document).ready(function () {
    //validation - make sure this is included after jquery.validate.unobtrusive.js
    //unobtrusive validate plugin overrides all defaults, so override them again
    $('form').each(function () {
        OverrideUnobtrusiveSettings(this);
    });
    //in case someone calls $.validator.unobtrusive.parse, override it also
    var oldUnobtrusiveParse = $.validator.unobtrusive.parse;
    $.validator.unobtrusive.parse = function (selector) {
        oldUnobtrusiveParse(selector);
        $('form').each(function () {
            OverrideUnobtrusiveSettings(this);
        });
    };
    //replace validation settings function
    function OverrideUnobtrusiveSettings(formElement) {
        var settngs = $.data(formElement, 'validator').settings;
        //standard qTip2 stuff copied from sample
        settngs.errorPlacement = function (error, element) {
            // Set positioning based on the elements position in the form
            var elem = $(element);


            // Check we have a valid error message
            if (!error.is(':empty')) {
                // Apply the tooltip only if it isn't valid
                elem.filter(':not(.valid)').qtip({
                    overwrite: false,
                    content: error,
                    position: {
                        my: 'center left',  // Position my top left...
                        at: 'center right', // at the bottom right of...
                        viewport: $(window)
                    },
                    show: {
                        event: false,
                        ready: true
                    },
                    hide: false,
                    style: {
                        classes: 'qtip-red' // Make it red... the classic error colour!
                    }
                })
                // If we have a tooltip on this element already, just update its content
                .qtip('option', 'content.text', error);
            }

            // If the error is empty, remove the qTip
            else { elem.qtip('destroy'); }
        };

        settngs.success = $.noop;
    }
});
Diallage answered 18/12, 2012 at 8:49 Comment(1)
This worked great but it doesnt seem to be applying the classes: 'qtip-red' in my mvc project. I always get the yellow? Any ideas why it would do this?Nickelodeon
E
2

Found the answer... posting for reference.

1) First, locate the script jquery.validate.unobtrusive.js provided by microsoft.

2) Second, on the script locate the function validationInfo(form) and replace the errorPlacement instruction in the options structure with the one provided by qTip, or any of your choice.

3) Same goes for style and other options you wish to change in how validation is handled.

4) Include all necessary files were needed.

Hope this helps someone having a similar problem.

Example Code:

function validationInfo(form) {
    var $form = $(form),
        result = $form.data(data_validation);

    if (!result) {
        result = {
            options: {  // options structure passed to jQuery Validate's validate() method
                //errorClass: "input-validation-error",
                errorClass: "error",
                errorElement: "span",
                //errorPlacement: $.proxy(onError, form),
                errorPlacement: function (onError, form) {
                    var error = onError;
                    var element = form;
                    // Set positioning based on the elements position in the form
                    var elem = $(element),
                        corners = ['left center', 'right center'],
                        flipIt = elem.parents('span.right').length > 0;

                    // Check we have a valid error message
                    if (!error.is(':empty')) {
                        // Apply the tooltip only if it isn't valid
                        elem.filter(':not(.valid)').qtip({
                            overwrite: false,
                            content: error,
                            position: {
                                my: corners[flipIt ? 0 : 1],
                                at: corners[flipIt ? 1 : 0],
                                viewport: $(window)
                            },
                            show: {
                                event: false,
                                ready: true
                            },
                            hide: false,
                            style: {
                                classes: 'ui-tooltip-red' // Make it red... the classic error colour!
                            }
                        })

                        // If we have a tooltip on this element already, just update its content
                        .qtip('option', 'content.text', error);
                    }

                    // If the error is empty, remove the qTip
                    else { elem.qtip('destroy'); }
                },
                invalidHandler: $.proxy(onErrors, form),
                messages: {},
                rules: {},
                success: $.proxy(onSuccess, form)
            },
            attachValidation: function () {
                $form.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;
}
Epizoon answered 25/7, 2011 at 15:42 Comment(2)
Thanks for the tip above but the changes in the jquery.validate.unobtrusive.js file makes it so that the form submits even if there are errors. How do you restore the default behavior where the form doesn't submit when there are errors?Schluter
@ Nick-Olsen - Personally, every submit I make is with jQuery Ajax, to before making the Ajax call, I validate the form explicitly like this: if (!$(this).valid()) return false; However, please take note that since I first posted this solution, I made an improvement which solves some problems I have with this particular scenerio... I'll add it as another answer so you can see it.Epizoon
M
0

With Mantisimo & AJC answers (thanks to him), I written the following script, it's OK and it works without any problems but jquery.validate.unobtrusive.js throws an error as the following in each submitting form :

$(document).ready(function () {
    var $forms = $.data($('form')[0], 'validator');
    if ($forms == undefined) return;
    var settngs = $forms.settings;
    settngs.errorPlacement = function (error, inputElement) {
        var element = inputElement;
        var elem = $(element),
            corners = ['left center', 'right center'],
            flipIt = elem.parents('span.right').length > 0;
        if (!error.is(':empty')) {
            elem.filter(':not(.valid)').qtip({
                overwrite: false,
                content: error,
                position: {
                    my: corners[flipIt ? 0 : 1],
                    at: corners[flipIt ? 1 : 0],
                    viewport: $(window)
                },
                show: {
                    event: false,
                    ready: true
                },
                hide: false,
                style: {
                    classes: 'qtip-red',
                }
            })
            .qtip('option', 'content.text', error);
        }
        else { elem.qtip('destroy'); }
    };
});

jquery.validate.unobtrusive.js error

I've tested with MVC 5 and qtip 2.2.0

Maneating answered 6/4, 2014 at 9:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.