Friday 7 October 2011

MVC 3: Disable submit button on invalid input

…or enable it on valid input :-)
In a previous post I talked about having the submit (save) button disabled until valid input.
But how do you do that? I’m going to show you a way to do it using MVC 3 and its support for unobtrusive javascript/ajax. Remember this is *a* way, not *the* way to do it. Feel free to criticize it any way you want :-)
First my View (with just a single field):
   1: <div id="RegistrationPanel">
   2:     @using (Html.BeginForm("Save", "Registration"))
   3:     {
   4:         <div class="editor-label">
   5:             @Html.LabelFor(m => m.Name)
   6:         </div>
   7:     
   8:         <div class="editor-field">
   9:             @Html.TextBoxFor(m => m.Name)
  10:             @Html.ValidationMessageFor(m => m.Name)
  11:         </div>
  12:     
  13:         <input type="submit" value="Register" />
  14:     }
  15: </div>


Then my Model:
   1: public class RegistrationModel
   2: {
   3:     [Required(ErrorMessage = "Required field")]
   4:     [DisplayName("Name")]
   5:     public string Name { get; set; }
   6: }
Nothing special, very straight forward, very simplified. Using the built in support in MVC 3 for unobtrusive validation. As a note you can see I’m not using the Ajax.BeginForm, because I don’t like it. To much “magic” a la WebForms. I want to know (and control) what’s going on.

But now, let’s get on with the button disabling stuff.

First make sure you include all the javascript files you need:
   1: <script src="@Url.Content("~/Scripts/jquery-1.6.2.min.js")" type="text/javascript"></script>
   2: <script src="@Url.Content("~/Scripts/jquery-ui-1.8.16.min.js")" type="text/javascript"></script>
   3: <script src="@Url.Content("~/Scripts/modernizr-1.7.min.js")" type="text/javascript"></script>
   4: <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
   5: <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
   6: <script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>

The modernizr isn’t really needed here, but I include it anyway.

Then I also include a javascript file for my View. It contains all the “good” stuff:
   1: var Registration = (function () {
   2:     var form;
   3:     var submitButton;
   4:   
   5:     return {
   6:         Init: function () {
   7:             form = $('#RegistrationPanel form');
   8:             submitButton = form.find('input[type=submit]');
   9:             submitButton.button();
  10:  
  11:             // Get jquery validator object
  12:             var validator = form.data('validator');
  13:             // Hook into the jquery validator showErrors event
  14:             validator.settings.showErrors = function () {
  15:                 var nrOfInvalids = this.numberOfInvalids();
  16:                 var buttonVerb = (nrOfInvalids > 0) ? 'disable' : 'enable';
  17:                 submitButton.button(buttonVerb);
  18:                 this.defaultShowErrors(); // also execute default action
  19:             };
  20:   
  21:             form.submit(function () {
  22:                 if (form.valid()) {
  23:                     $.post(form.attr('action'), form.serialize(), function (jsonData) {
  24:                         // Notify user about success
  25:                     },
  26:                     'json');
  27:                 }
  28:                 return false;
  29:             });
  30:         }
  31:     };
  32: })();
  33:  
  34: $(function() {
  35:     Registration.Init();
  36: });
That does it! I hook up to an event in the jquery validator showErrrors event http://docs.jquery.com/Plugins/Validation/validate#toptions (for disabling/enabling submit button).

This also keeps the server validation (TryUpdateModel).

1 comment:

  1. Nice one!!! Works with MVC5 and preserves existing validation. Thanks!!

    ReplyDelete