Question

Posting this here in case someone else has the same problem...

When using a select2 dropdown in a C# MVC4 site, the page is not scrolled to the correct position when validation fails. Validation as such works and error scrolling also works for other controls, just not select2's. The reason AFAICS is that select2 replaces the original select with it's own markup and then set the original select as display:none. jquery.validate then has no valid target to scroll to.

We are using twitter bootstrap for styling, but I don't think it has any impact on this problem.

Was it helpful?

Solution

The jquery.validate documentation (as well as many answers here on StackOverflow) suggests that you use $.validator.setDefaults to assign the invalidHandler, but I couldn't get this to work in asp.net (it does work for focusInvalid however), probably due to us using the MS unobtrusive library. Instead I used this code in my jquery ready handler:

    $(function() {
        $.validator.setDefaults({         
            focusInvalid: false
        });

        function scrollToError(error, validator) {
            var elem = $(validator.errorList[0].element);
            if (elem.length) {
                if (elem.is(':visible'))
                    return elem.offset().top - 16;
                elem = elem.prev($(".select2-container"));
                if (elem.length) {
                    return elem.offset().top - 16;
                }
            }
            return 0; // scroll to top if all else fails
        }

        $('form').bind('invalid-form.validate', function(error, validator) {
            // fix scrolling and validation for select2

            if (!validator.numberOfInvalids())
                return;

            $('html, body').animate({
                scrollTop: scrollToError(error, validator)
            }, 500);
        });
...

I set focusInvalid to false to disable and avoid conflict with the standard scroll and focus behavior.

The bind() call is used instead of the invalidHandler option and is the same as used by the validate plugin.

scrollToError() selects the first invalid element and returns the position to scroll to, either a normal visible element or a previous item with the 'select2-container' class (i.e a select2 element) or top of page if all else fails.

Standard behavior (showing validation errors etc) still works as before.

Hope this helps someone and if you have a better solution I would be very interested in knowing about it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top