Skip to content

Instantly share code, notes, and snippets.

@lukesutton
Last active December 24, 2015 22:59
Show Gist options
  • Select an option

  • Save lukesutton/6876158 to your computer and use it in GitHub Desktop.

Select an option

Save lukesutton/6876158 to your computer and use it in GitHub Desktop.
The start of a 'dirty' input tracking plugin. It's been done a bajillion times, but this one is simple.
/* -------------------------------------------------------------------------- */
/* DIRTY FORM
/* Checks to see if the user has made any changes to a form. Toggles the save
/* control on or off appropriately. Also prompts user to save it they attempt
/* to navigate away with unsaved changes.
/* -------------------------------------------------------------------------- */
(function($) {
var DirtyForm = function(form) {
this.$form = form;
this.$save = form.find('button.save');
var inputs = form.find(':input:not([type=hidden], button)');
this.originalValues = _.reduce(inputs, function(memo, el) {
var $el = $(el);
if (!$el.is(':radio, :checkbox') || $el.is(':checked')) {
memo[$el.attr('name')] = {
value: $.trim($el.val()),
dirty: false
};
}
return memo;
}, {});
this.setPristine();
inputs.on('change', $.proxy(this, 'change'));
$(window).on('beforeunload', $.proxy(this, 'navigate'));
};
DirtyForm.prototype = {
change: function(e) {
var $input = $(e.target)
original = this.originalValues[$input.attr('name')],
val = $.trim($input.val());
original.dirty = (original.value !== val);
var dirty = _.some(_.pluck(this.originalValues, 'dirty'));
if (dirty) {
this.setDirty();
}
else {
this.setPristine();
}
},
setDirty: function() {
this.dirty = true;
this.$save.prop('disabled', false).css('opacity', 1);
},
setPristine: function() {
this.dirty = false;
this.$save.prop('disabled', true).css('opacity', 0.5);
},
navigate: function() {
if (this.dirty) {
if (window.confirm("DERP")) {
}
else {
// supress event
}
}
}
};
$.fn.islayDirtyForm = function() {
this.each(function() {
var $this = $(this);
if (!$this.data('islayDirtyForm')) {
$this.data('islayDirtyForm', new DirtyForm($this));
}
});
return this;
};
})(jQuery);
(function($) {
function DirtyForm($el, opts) {
this.$el = $el;
this._dirty = false;
this._originalValues = {};
this.settings = $.extend({
// Add default settings here.
}, opts);
// Subscribe to any event on the form
var inputs = form.find(':input:not([type=hidden], button)');
for (var i = 0; i < inputs.length; i++) {
var $el = $(inputs[i]);
if (!$el.is(':radio, :checkbox') || $el.is(':checked')) {
this._originalValues[$el.attr('name')] = {value: $.trim($el.val()), dirty: false};
}
};
inputs.on('change', $.proxy(this, '_change'));
if (this.settings.preventNavigation) {
$(window).on('beforeunload', $.proxy(this, '_navigate'));
}
}
DirtyForm.prototype = {
isDirty: function() {
return this._dirty;
},
_change: function() {
var $input = $(e.target)
original = this._originalValues[$input.attr('name')],
val = $.trim($input.val());
original.dirty = (original.value !== val);
var dirty = _.some(_.pluck(this.originalValues, 'dirty'));
if (dirty) {
this._dirty = true;
this.$el.trigger('dirty', true);
}
else {
this._dirty = false;
this.$el.trigger('dirty', false);
}
},
_navigate: function() {
},
_run: function(name, args) {
if (typeof this[name] === "function") {
return this[name].apply(this, args);
}
else {
throw "$.fn.dirtyForm does not have a function called " + name;
}
}
};
$.fn.dirtyForm = function() {
var args = Array.prototype.slice.call(arguments);
for (var i = 0; i < this.length; i++) {
var $this = $(this[i]);
if (!$this.is('form')) {
throw "$.fn.dirtyForm can only be called on form elements";
}
if ($this.data('dirtyForm')) {
return $this.data('dirtyForm')._run(args.shift(), args);
}
else {
$this.data('dirtyForm', new DirtyForm($this, args[0]));
}
});
return this;
};
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment