MVC: Check if Is Dirty via #JavaScript

I had a need to do some fancy work on a MVC Razor page enabling and disabling buttons based on various criteria.  To do this I needed to check to see if the user had changed any data on the page I ended up using the following structure to do it.

First set up your page with a form and all your input fields.

@using(Html.BeginForm("actionname", "controllername", new { area = "areaname" }, 
       FormMethod.Post, new { id = "saveForm", @class = "disable-submit-form" }))
{
     /* lots of page code */
}

This method serializes the data into a Name, Value array of objects  and hashes it.

     // Grab all the data fields in the code and serialize them, then hash them
     // @Html.Checkbox and CheckBoxFor need to be handled as a separate case 
     function GetSerializedItems() {
        var serializedArray = $(".disable-submit-form").serializeArray()
                                 .filter(function (item) { 
                                           return item.name != 'CheckboxItem1' 
                                               && item.name != 'CheckboxItem2'; 
                                         });
        var serializedCheckboxItems = $('input:checkbox').map(
                                        function () { 
                                           return { name: this.name, 
                                                    value: this.checked ? this.value 
                                                                        : "false" }; 
                                        });
        for (var index = 0; index < serializedCheckboxItems.length; ++index) {
           serializedArray.push(serializedCheckboxItems[index]);
        }
        return convertSerializedArrayToHash(serializedArray);
      }

      $(document).ready(function () {
        // Get the initial state of the data on the page.
        var startItems = GetSerializedItems(); 
       
        // On each field change recheck the current button state
        $('.disable-submit-form').on('change', function () {
           showhidebuttons();
        });

      function showhidebuttons() {
        var $form = $(".disable-submit-form");
        var currentItems = GetSerializedItems();
        var dirty = hashDiff(startItems, currentItems);
        var isDirty = countProperties(dirty) > 0;
        var isValid = $form.valid();
        var isDraft = '@Model.IsDraft' === 'True';

        $form.find(".submitform").attr('disabled', 'disabled');

        if (isValid && isDirty) {
          $form.find(".submitform").removeAttr('disabled');
        } else if (isDraft && isValid) {
          $form.find("#PreviewId").removeAttr('disabled');
          $form.find("#PublishId").removeAttr('disabled');
        }
      }
     }
     
     //Call ShowHideButtons to set the default state
     showhidebuttons();

Here are the javascript helpers I used.

 function convertSerializedArrayToHash(a) {
 var r = {};
 for (var i = 0; i < a.length; i++) {
 r[a[i].name] = a[i].value;
 }
 return r;
 }

 function hashDiff(h1, h2) {
 var d = {};
 for (k in h2) {
 if (h1[k] !== h2[k]) d[k] = h2[k];
 }
 return d;
 }

 function countProperties(obj) {
 var count = 0;

 for (var prop in obj) {
 if (obj.hasOwnProperty(prop))
 ++count;
 }

 return count;
 }

Leave a comment