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;
}