30

I'm using ASP.NET 2.0 with a Master Page, and I was wondering if anyone knew of a way to detect when the fields within a certain <div> or fieldset have been changed (e.g., marked 'IsDirty')?

10 Answers 10

56

You could bind the Change event for all inputs and flag a variable as true. Like this.

var somethingChanged = false;
$(document).ready(function() { 
   $('input').change(function() { 
        somethingChanged = true; 
   }); 
});

But, keep in mind that if the user changes something, then changes back to the original values, it will still be flagged as changed.

UPDATE: For a specific div or fieldset. Just use the id for the given fieldset or div. Example:

var somethingChanged = false;
$(document).ready(function() { 
   $('#myDiv input').change(function() { 
        somethingChanged = true; 
   }); 
});
Sign up to request clarification or add additional context in comments.

10 Comments

Is there anyway to do this for the inputs within a given fieldset or div tag?
Yes, just use add the id of the given fieldset or div in the selector using #id.
Thanks jose. I'll try this and get back to you if i have any questions
Be aware that this solution leads to an undesiderable behaviour when dealing with UI. See my answer please.
I would highly recommend one replaces $('input') with $(':input') -- The colon will match all types of inputs rather than input <input> tags. Eg: input, textarea, select.
|
32

Quick (but very dirty) solution

This is quick, but it won't take care of ctrl+z or cmd+z and it will give you a false positive when pressing shift, ctrl or the tab key:

$('#my-form').on('change keyup paste', ':input', function(e) {
    // The form has been changed. Your code here.
});

Test it with this fiddle.


Quick (less dirty) solution

This will prevent false positives for shift, ctrl or the tab key, but it won't handle ctrl+z or cmd+z:

$('#my-form').on('change keyup paste', ':input', function(e) {

  var keycode = e.which;

  if (e.type === 'paste' || e.type === 'change' || (
      (keycode === 46 || keycode === 8) || // delete & backspace
      (keycode > 47 && keycode < 58) || // number keys
      keycode == 32 || keycode == 13 || // spacebar & return key(s) (if you want to allow carriage returns)
      (keycode > 64 && keycode < 91) || // letter keys
      (keycode > 95 && keycode < 112) || // numpad keys
      (keycode > 185 && keycode < 193) || // ;=,-./` (in order)
      (keycode > 218 && keycode < 223))) { // [\]' (in order))

    // The form has been changed. Your code here.

  }

});

Test it with this fiddle.


A complete solution

If you want to handle all the cases, you should use:

// init the form when the document is ready or when the form is populated after an ajax call
$(document).ready(function() {
  $('#my-form').find(':input').each(function(index, value) {
    $(this).data('val', $(this).val());
  });
})

$('#my-form').on('change paste', ':input', function(e) {
  $(this).data('val', $(this).val());
  // The form has been changed. Your code here.
});

$('#my-form').on('keyup', ':input', function(e) {
  if ($(this).val() != $(this).data('val')) {
    $(this).data('val', $(this).val());
    // The form has been changed. Your code here. 
  }
});

Test it with this fiddle.

3 Comments

The jquery method "live()" has been deprecated. You can use "on" instead. $('select').on('change', function......
I edited the answer for a even better solution, based on the post stackoverflow.com/questions/203198/…. Thanks a lot, Luca
You could just have used .prop( 'defaultValue' ).
28

A simple and elegant solution (it detects form elements changes in real time):

var formChanged = false;

$('#my-div form').on('keyup change paste', 'input, select, textarea', function(){
    formChanged = true;
});

8 Comments

Love it. I replaced 'input, select, textarea' with :input for simplicity though ;)
@Marcio Mazzucato May you tell me why do you need event 'keyup' over here? Thank you for your explanation.
@Thomas.Benz, Sure! Because .change() event fires only when selector has lost focus. You can see more info in this answer.
@Thomas.Benz, I am not using :input only for an easier readability, but you can implement it. For the case you mentioned, you can use the paste event, i updated the answer right now, thanks!
@Marcio Mazzucato Perfect. Now "the mouse copying and pasting data also making form input changes" is included.
|
13

For a form you could serialize the contents on load then compare serialization at a later time, e.g.:

$(function(){
    var initdata=$('form').serialize();
    $('form').submit(function(e){
        e.preventDefault();
        var nowdata=$('form').serialize();
        if(initdata==nowdata) console.log('nothing changed'); else console.log('something changed');
        // save
        initdata=nowdata;
        $.post('settings.php',nowdata).done(function(){
            console.log('saved');
        });
    });
});

Note this requires form elements to have a name attribute.

1 Comment

Thanks for this! Your solution is extremely elegant, simple and works with forms containing arrays of values.
5

Just to clarify because the question is "within a certain fieldset/div":

var somethingChanged = false;
$(document).ready(function() { 
   $('fieldset > input').change(function() { 
        somethingChanged = true; 
   }); 
});

or

var somethingChanged = false;
$(document).ready(function() { 
   $('div > input').change(function() { 
        somethingChanged = true; 
   }); 
});

1 Comment

You can replace the fieldset or div with the ID or class of them to get specific fieldsets or divs.
4

You can give the fieldset or div an ID and bind the change event to it ... the event should propagate from the inner children.

var somethingChanged = false;
$('#fieldset_id').change(function(e)
{
    // e.target is the element which triggered the event
    // console.log(e.target);
    somethingChanged = true;
});

Additionally if you wanted to have a single event listening function you could put the change event on the form and then check which fieldset changed:

$('#form_id').change(function(e)
{
    var changedFieldset = $(e.target).parents('fieldset');
    // do stuff
});

2 Comments

good article on JS event delegation ... sitepoint.com/blogs/2008/07/23/…
That's the best solution. Thank you! Although it still ignores when input values change dinamically.
2

I came up with this piece of code in CoffeeScript (not really field tested, yet):

  • Add class 'change_warning' to forms that should be watched for changes.

  • Add class 'change_allowed' to the save button.

change_warning.coffee:

window.ChangeWarning = {
    save: ->
        $(".change_warning").each (index,element) ->
            $(element).data('serialized', $(element).serialize())

    changed: (element) ->
        $(element).serialize() != $(element).data('serialized')

    changed_any: ->
        $.makeArray($(".change_warning").map (index,element) -> ChangeWarning.changed(element)).some (f)->f
        # AKA $(".change_warning").any (element) -> ChangeWarning.changed(element)
        # But jQuery collections do not know the any/some method, yet (nor are they arrays)

    change_allowed: ->
        ChangeWarning.change_allowed_flag = true

    beforeunload: ->
        unless ChangeWarning.change_allowed_flag or not ChangeWarning.changed_any()
            "You have unsaved changes"
}

$ ->
    ChangeWarning.save()
    $(".change_allowed").bind 'click', -> ChangeWarning.change_allowed()
    $(window).bind 'beforeunload',     -> ChangeWarning.beforeunload()

Comments

1

An alternative to Dw7's answer if you only want the fields inside a fieldset then you can call serialize() on its input values. Note: serialize() will not pickup any elements that do not have a "name" attribute. This will work for select tags as well.

var initialValues = $('#your-fieldset :input').serialize();

$('form').submit(function(e) {
  e.preventDefault();
  var currentValues = $('#your-fieldset :input').serialize();
  if (currentValues == initialValues) {
    // Nothing has changed
    alert('Nothing was changed');
  }
  else {
    this.submit();
  }
});

Comments

0

.live is now deprecated and replaced by .on:

var confirmerSortie = false;
$(document).on('change', 'select', function() {
    confirmerSortie = true;
});

$(document).on('change keypress', 'input', function() {
    confirmerSortie = true;
});

$(document).on('change keypress', 'textarea', function() {
    confirmerSortie = true;
});

Comments

0

The following solution worked for me:

$("#myDiv :input").change(function() { $("#myDiv").data("changed",true);});
}
  
if($("#myDiv").data("changed")) {
console.log('Form data changed hence proceed to submit');  
}
else {
console.log('No change detected!');
}

Thanks

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.