Topic: Unobtrusive Validation

kinetiq priority asked 6 years ago


I am trying to hack your validation a bit to work better with Unobtrusive Validation for jQuery. In mdb.js, I see that the file is a dump of all your plugins. I figured out that one of them is forms-js, so I set about trying to learn more about this. However, I think I'm looking in the wrong place. I found this: https://github.com/bvaughn/forms-js/blob/master/dist/forms-js.js But of course that code does not line up with what I see in mdb.js, at all. Can you point me in the right direction please? Also, any tips about getting this to work with Unobtrusive Validation would be greatly appreciated. Not sure what to put in version number. Thanks!

Jakub Strebeyko staff commented 6 years ago

Hi there kinetiq, Thanks for reaching out. I must admit, it's the first time I come across Unobtrusive Validation, so I won't be of much help when it comes to implementation per se, but majority of MDB UI components are prone to html5 validation applied through appropriate attributes. Besides that, the input fields are eligible for any kind of JavaScript manipulation (i.e. onfocusout="myFunction()"), so sky is the limit. What exactly are you looking for? Best Regards, Kuba

kinetiq priority commented 6 years ago

That is helpful, thanks! I've been learning more about the Constraint Validation API, which is html5's native validation, which you guys seem to use. The trick here is just going to be around some re-mapping of CSS classes I think. Unobtrusive Validation is an open source jQuery library used by ASP.NET MVC (and MVC Core) among other things... It is very similar to html5's validation, but it uses different attributes and CSS classes, and also the API is older and a bit less flexible. I know this is likely to provoke a response of "we don't support MVC" and that's fine. I wanted to mention that MDB seems to work great with MVC aside from validation, and supporting Unobtrusive Validation could make your product easy to use for millions of developers without you having to go the full distance of answering questions related to Microsoft's stack. You are actually *almost* a great candidate for ASP.NET MVC projects because MVC uses bootstrap by default, and MDB is basically better bootstrap. One last word here to give you a bit more context... In MVC, we typically create a server-side model for every page. The model contains fields, and we can decorate the fields with validation attributes that work on the server, but that also trickle down to HTML automatically, providing a solid validation experience with, quite often, no code at all. This automation of validation is an important feature in MVC, and it relies on Unobtrusive Validation on the client, which is why no .NET dev is likely to be excited about any other validation framework, and will likely bounce when they find you, love you, and can't make this part work. In my mind this might be a missed opportunity. Hope that helps. I am going over your validation code, which is really only a couple pages long, and trying to make this work. :)

kinetiq priority commented 6 years ago

So, I seem to have this working. In mdb.js, starting on line 14023, which says: /* FORMS */, replaced that whole section with this: /* FORMS */ (function ($) { $(document).ready(function () { // Text based inputs var input_selector = ['text', 'password', 'email', 'url', 'tel', 'number', 'search', 'search-md'].map(function (selector) { return 'input[type=' + selector + ']'; }).join(', ') + ', textarea'; var text_area_selector = '.materialize-textarea'; var update_text_fields = function update_text_fields($input) { var $labelAndIcon = $input.siblings('label, i'); var hasValue = $input.val(); var valid = !$input.hasClass('invalid'); var hasPlaceholder = $input.attr('placeholder') !== undefined; var addOrRemove = (!valid || hasValue || hasPlaceholder ? 'add' : 'remove') + 'Class'; $labelAndIcon[addOrRemove]('active'); }; var validate_field = function validate_field($input) { if ($input.hasClass('validate')) { var value = $input.val(); var noValue = !value.length; var isValid = !$input[0].validity.badInput; if (noValue && isValid) { $input.removeClass('valid').removeClass('invalid'); } else { var valid = $input.is(':valid'); var length = Number($input.attr('length')) || 0; if (valid && (!length || length > value.length)) { $input.removeClass('invalid').addClass('valid'); } else { $input.removeClass('valid').addClass('invalid'); } } } }; var textarea_auto_resize = function textarea_auto_resize() { var $textarea = $(undefined); if ($textarea.val().length) { var _$hiddenDiv = $('.hiddendiv'); var fontFamily = $textarea.css('font-family'); var fontSize = $textarea.css('font-size'); if (fontSize) { _$hiddenDiv.css('font-size', fontSize); } if (fontFamily) { _$hiddenDiv.css('font-family', fontFamily); } if ($textarea.attr('wrap') === 'off') { _$hiddenDiv.css('overflow-wrap', 'normal').css('white-space', 'pre'); } _$hiddenDiv.text($textarea.val() + '\n'); var content = _$hiddenDiv.html().replace(/\n/g, '<br>'); _$hiddenDiv.html(content); // When textarea is hidden, width goes crazy. // Approximate with half of window size _$hiddenDiv.css('width', $textarea.is(':visible') ? $textarea.width() : $(window).width() / 2); $textarea.css('height', _$hiddenDiv.height()); } }; // Set active on labels and icons (DOM ready scope); $(input_selector).each(function (index, input) { var $this = $(input); update_text_fields($this); }); // Add active when element has focus $(document).on('focus', input_selector, function (e) { $(e.target).siblings('label, i').addClass('active'); }); // Remove active on blur when not needed or invalid $(document).on('blur', input_selector, function (e) { var $this = $(e.target); var hasValue = $this.val(); var valid = !$this.hasClass('invalid'); var hasPlaceholder = $this.attr('placeholder') !== undefined; if (valid && !(hasValue || hasPlaceholder)) { $this.siblings('label, i').removeClass('active'); } }); // Add active if form auto complete $(document).on('change', input_selector, function (e) { var $this = $(e.target); update_text_fields($this); validate_field($this); }); // Handle HTML5 autofocus $('input[autofocus]').siblings('label, i').addClass('active'); // HTML form reset $(document).on('reset', function (e) { var $formReset = $(e.target); if ($formReset.is('form')) { var $formInputs = $formReset.find(input_selector); // Reset inputs $formInputs.removeClass('valid').removeClass('invalid').each(function (index, input) { var $this = $(input); var noDefaultValue = !$this.val(); var noPlaceholder = !$this.attr('placeholder'); if (noDefaultValue && noPlaceholder) { $this.siblings('label, i').removeClass('active'); } }); // Reset select $formReset.find('select.initialized').each(function (index, select) { var $select = $(select); var $visible_input = $select.siblings('input.select-dropdown'); var default_value = $select.children('[selected]').val(); $select.val(default_value); $visible_input.val(default_value); }); } }); // Textarea Auto Resize if (!$('.hiddendiv').first().length) { $hiddenDiv = $('<div class="hiddendiv common"></div>'); $('body').append($hiddenDiv); } $(text_area_selector).each(textarea_auto_resize); $('body').on('keyup keydown', text_area_selector, textarea_auto_resize); }); })(jQuery); 'use strict'; I mostly changed the way we're checking validity... Instead of consulting the native html5 validation, I check for the 'invalid' class, which in this case is set by Unobtrusive. Speaking of which, unobtrusive validation needs some config. Like MDB, it marks the element with a class when invalid. Unfortunately, it's a different class so it doesn't work with MDB's css... So, this needs to go in your JS chain, *after* the unobtrusive validation file. The sequence is important. $.validator.unobtrusive.options = { errorClass: "invalid" } After that, it seems to just work. Here's an example of my MVC .NET Core 2 model and view: Model... public class FirmVM { public int Id { get; set; } [Required] [StringLength(100)] public string Name { get; set; } } And in the view.. <div class="md-form"> <i class="fa fa-user prefix"></i> <input asp-for="Name" class="form-control" autocomplete="off" /> <label asp-for="Name" data-error="invalid"></label> </div> And that's it. Might need some tweaking and some more cleanup in the JS... In particular, there's something in that JS that appears to be a vestige of materialize. There's a lot of code that revolves around .materialize-textarea, which does not appear in the CSS or anywhere else in MDB as far as I can tell. But it is probably there for a reason, so I left it alone.

Jakub Strebeyko staff commented 6 years ago

Hi there kinetiq, Reading your report was food for thought and honestly - I just brought it up upstairs. We will be definitely looking into this suggestion and, perhaps, rethinking our old ways. Meanwhile - thanks tenfold for your effort, it is appreciated. With Best Regards, Kuba

Jeffrey Hermosa free commented 4 years ago

This is exactly what I was looking for, mdb guys please make your validation work seamlessly with jquery unobtrusive validation used by .net developers



Please insert min. 20 characters.

FREE CONSULTATION

Hire our experts to build a dedicated project. We'll analyze your business requirements, for free.

Status

Resolved

Specification of the issue

  • ForumUser: Priority
  • Premium support: Yes
  • Technology: MDB jQuery
  • MDB Version: -
  • Device: -
  • Browser: -
  • OS: -
  • Provided sample code: No
  • Provided link: No
Tags