0

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.

peter3
  • 1,074
  • 13
  • 22
  • Yes, the jQuery Validate plugin will ignore hidden elements by default. The fix is to simply set the `ignore` option to `[]`, which disables this default behavior. See: http://stackoverflow.com/a/8565769/594235 – Sparky Sep 17 '13 at 16:59
  • True but the hidden element is still not the one we want to scroll to – peter3 Sep 18 '13 at 11:18

1 Answers1

4

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.

peter3
  • 1,074
  • 13
  • 22
  • Perfect solution peter3! Still valid in 2022! This is the answer to smooth scrolling to any invalid field including both inputs and selects. Just update the elem.offset().top - ?? to whatever value you want so the first invalid field scrolls into view and well below the top menu bar. – Joshua Aug 31 '22 at 21:10
  • Ha! I don't know any other answer I've ever provided that is still valid almost 9 years later! :D – peter3 Sep 07 '22 at 22:10