DmitryEfimenko / TwitterBootstrapMvc

Fluent implementation of ASP.NET-MVC HTML helpers for Twitter Bootstrap.
Apache License 2.0
224 stars 79 forks source link

Fix for TwitterBootstrapJs.js to fix the order which the scripts (jQuery Validation * and TwitterBootstrapJs.js) must be included #211

Closed Jak3b0 closed 10 years ago

Jak3b0 commented 10 years ago

Hi,

I was playing around with unobtrusive validation and your library and I was having a hard time getting the validation state to kick in.

I realized that the order that I was loading the validation scripts (jQuery Validation, jQuery Validation Unobtrusive and yours) had something to do with it. I had to load BMVC first.

Another way for me to get it working was to put the validator.setDefaults() outside the $(document).ready() function.

Then, after a bit of searching, I came across this answer on StackOverflow (http://stackoverflow.com/a/14574974/767080). I am not an expert with jQuery (and Javascript for that matter) but I tried his solution to use $("form").validate().settings to set the highlight and unhighlight functions leaving it inside the $(document).ready() function and everything is working great. The order that the scripts are loaded don't matter anymore.

Maybe this is something you could have a look at and, if it is good, put it in your script.

Hope this helps! :)

DmitryEfimenko commented 10 years ago

could you please post the full version of modified TwitterBootstrapMvcJs.js file that you ended up with?

Jak3b0 commented 10 years ago

Sure! Here you go. Note that I also added .has('li') to where you were adding the alert alert-danger to the bmvc-3-validation-summary so that the validation summary doesn't show if there is not content. In my case, I do not use the validation summary to display errors for each fields. When doing client-side validation, the validation summary was showing all the time.

$(document).ready(function () {
  $('form').bind('invalid-form.validate', function (form) {
    $('.bmvc-3-validation-summary').has('li').addClass('alert alert-danger').find('.close').show();
  });

  $('form').validate().settings.highlight = function (element) {
    $(element).closest('.control-group').addClass('error');
    $(element).closest('.form-group').addClass('has-error');
  };
  $('form').validate().settings.unhighlight = function (element) {
    $(element).closest('.control-group').removeClass('error');
    $(element).closest('.form-group').removeClass('has-error');
  };

  $('[rel=tooltip]').tooltip();
  $('[rel=popover]').popover();

  $(function () {
    if ($('[data-bmvc-confirm]').length > 0) {
      if (typeof BootstrapDialog != 'undefined') {
        BootstrapDialog.bmvcConfirm = function (message, title, callback) {
          new BootstrapDialog({
            title: title,
            message: message,
            closable: false,
            data: {
              'callback': callback
            },
            buttons: [{
              label: 'Cancel',
              action: function (dialog) {
                dialog.close();
              }
            }, {
              label: 'OK',
              cssClass: 'btn-primary',
              action: function (dialog) {
                typeof dialog.getData('callback') === 'function' && dialog.getData('callback')(true);
              }
            }]
          }).open();
        };

        $(document).on('click', '[data-bmvc-confirm]', function (e) {
          e.preventDefault();
          var self = $(this);
          var title = self.attr('data-bmvc-confirm-title');
          if (title === undefined) {
            title = 'Confirmation';
          }
          var text = self.attr('data-bmvc-confirm-text');
          var href = self.attr('href');
          BootstrapDialog.bmvcConfirm(text, title, function () {
            window.location = href;
          });
        });
      } else {
        alert('You need http://nakupanda.github.io/bootstrap3-dialog/ for the confirm to work');
      }
    }

    $('[data-provide=typeahead]').each(function () {
      var self = $(this);
      self.typeahead({
        source: function (term, process) {
          var url = self.data('url');

          return $.getJSON(url, { term: term }, function (data) {
            return process(data);
          });
        }
      });
    });

    $('[data-disabled-depends-on]').each(function () {
      var self = $(this);
      var name = self.data('disabled-depends-on');
      var val = self.data('disabled-depends-val');
      var selector = '[name="' + name + '"]';

      $(document).on('change', selector + ':checkbox', function () {
        self.prop('disabled', $(this).prop('checked') == val);
      });

      $(document).on('change', selector + ':not(:checkbox):not(:hidden)', function () {
        self.prop('disabled', $(this).val().toString() == val.toString());
      });
      if ($(selector).is(':radio')) {
        $(selector + ':checked').change();
      } else {
        $(selector).change();
      }
    });

    var isFirstRun = true;
    $('[data-visible-depends-on]').each(function () {
      var self = $(this);
      var name = self.data('visible-depends-on');
      var val = self.data('visible-depends-val');
      var speed = self.data('visible-depends-speed');
      var selector = '[name="' + name + '"]';
      var selfName = self.attr('name');
      var toHide;

      if (self.is('div')) {
        toHide = self;
      } else {
        var formGroup = self.closest('.form-group');
        if (formGroup.length > 0 && formGroup.find('input:not(:hidden):not([name="' + selfName + '"]),select:not([name="' + selfName + '"]),textarea:not([name="' + selfName + '"])').length === 0) {
          toHide = formGroup;
        } else {
          toHide = $('[name="' + selfName + '"],label[for="' + selfName + '"]');
        }
      }

      $(document).on('change', selector + ':checkbox', function () {
        if ($(this).prop('checked') == val) {
          toHide.show(isFirstRun ? undefined : speed);
        } else {
          toHide.hide(isFirstRun ? undefined : speed);
        }
      });

      $(document).on('change', selector + ':not(:checkbox):not(:hidden)', function () {
        if ($(this).val().toString() == val.toString()) {
          toHide.show(isFirstRun ? undefined : speed);
        } else {
          toHide.hide(isFirstRun ? undefined : speed);
        }
      });

      if ($(selector).is(':radio')) {
        $(selector + ':checked').change();
      } else {
        $(selector).change();
      }
      isFirstRun = false;
    });
  });
});
DmitryEfimenko commented 10 years ago

I've updated js file with these changes. Thanks for suggestion.