Wie gehen Sie mit einer Formularänderung in jQuery um?

81

Gibt es in jQuery eine einfache Möglichkeit zu testen, ob sich eines der Elemente eines Formulars geändert hat?

EDIT: Ich hätte hinzufügen sollen, dass ich nur ein click()Ereignis überprüfen muss .

EDIT: Sorry, ich hätte wirklich genauer sein sollen! Angenommen, ich habe ein Formular und eine Schaltfläche mit den folgenden Angaben:

$('#mybutton').click(function() {
  // Here is where is need to test
  if(/* FORM has changed */) {
     // Do something
  }
});

Wie würde ich testen, ob sich das Formular seit dem Laden geändert hat?

Mike
quelle
Meinen Sie damit die Aktion eines anderen Skripts, das auf der Seite enthalten ist, oder sobald der Benutzer Text eingegeben oder ein Radio / Kontrollkästchen angeklickt hat?
FelipeAls
Ich hätte hinzufügen sollen, dass ich nur ein click ()
-Ereignis

Antworten:

139

Du kannst das:

$("form :input").change(function() {
  $(this).closest('form').data('changed', true);
});
$('#mybutton').click(function() {
  if($(this).closest('form').data('changed')) {
     //do something
  }
});

Diese Rigs eines changeEvent - Handler - Eingänge in Form, wenn einer von ihnen es ändern verwendet .data()einen einstellen changedWert true, dann überprüfen wir nur für diesen Wert auf dem Klick, das davon ausgeht , dass im #mybuttonInnern der Form (wenn nicht nur ersetzen $(this).closest('form')mit $('#myForm')), aber Sie könnten es noch allgemeiner machen, wie folgt:

$('.checkChangedbutton').click(function() {
  if($(this).closest('form').data('changed')) {
     //do something
  }
});

Referenzen: Aktualisiert

Laut jQuery ist dies ein Filter zur Auswahl aller Formularsteuerelemente.

http://api.jquery.com/input-selector/

Der Eingangswähler: wählt grundsätzlich alle Formularsteuerelemente aus.

Nick Craver
quelle
6
Ist $('form :input')Konto für die Auswahl, Textarea und andere Eingabearten? oder ist es spezifisch für das Eingabe-Tag?
Val
6
Korrigieren Sie mich, wenn ich falsch liege, aber es scheint, dass diese Methode besagt, dass das Formular geändert wurde, auch wenn jemand eine Änderung vornimmt und diese dann rückgängig macht und manuell zu den ursprünglichen Werten im Formular zurückkehrt. In diesem Fall hätte sich das Formular in Bezug auf die Daten wirklich nicht geändert, aber diese Methode würde sagen, dass dies der Fall war.
Paul
1
Danke, ja, ich habe das versucht (es ist in einer anderen Antwort aufgeführt), aber es hat bei mir nicht funktioniert. Es scheint, dass es einige Sonderfälle gibt, die diese Methode ebenfalls auslösen. Derzeit arbeitet mit einem Plugin - github.com/codedance/jquery.AreYouSure
Paul
1
Gute Lösung für diesen Fall! Wenn jedoch jemand hier den Status des Formularinhalts abrufen möchte (z. B. "IsDirty"), sollten Sie dieser Lösung folgen: stackoverflow.com/a/26796840/665783
Jacob
1
@ Nick Craver: Was ist, wenn sich das Formularelement außerhalb des Formular-Tags mit dem Formularattribut als ID des Formulars befindet? Ich habe den Fall getestet, Pech, es funktioniert nicht.
Mahantesh
49

Wenn Sie überprüfen möchten, ob sich die Formulardaten, die an den Server gesendet werden sollen, geändert haben, können Sie die Formulardaten beim Laden der Seite serialisieren und mit den aktuellen Formulardaten vergleichen:

$(function() {

    var form_original_data = $("#myform").serialize(); 

    $("#mybutton").click(function() {
        if ($("#myform").serialize() != form_original_data) {
            // Something changed
        }
    });

});
Udi
quelle
5
Ausgezeichnet, dies ist die beste Lösung hier draußen. Vielen Dank.
Anonym
3
Ich habe diese Methode einmal angewendet und sie wurde sehr langsam, als die Form größer wurde. Dies ist eine gute Methode für kleine Formulare, aber nicht für große Formulare.
mkdevoogd
Meinst du Formulare mit Dateien?
Udi
1
Dies ist gut, aber es wäre besser, wenn Sie nicht jedes Mal überprüfen, wenn sich ein Steuerelement ändert, sondern direkt überprüfen, wann das Formular gesendet werden soll
Ruby Racer,
2
Dies ist viel besser, so dass Sie Schaltflächen wieder deaktiviert auslösen können, wie "Löschen"
EliuX
29

Eine Echtzeit- und einfache Lösung:

$('form').on('keyup change paste', 'input, select, textarea', function(){
    console.log('Form changed!');
});
Marcio Mazzucato
quelle
1
Sehr gute Lösung. Geeignet für die Eingabe der Formularüberprüfung.
Bijan
1
Die beste Lösung für mich! Vielen Dank.
Ivan
2
Ziehen Sie in Betracht, 'input'statt 'keyup change'Einfügen mit der rechten Maustaste zu verwenden, es sei denn, Sie müssen ältere Browser unterstützen.
TrueWill
10

Sie können mehrere Selektoren verwenden, um dem Änderungsereignis für jedes Formularelement einen Rückruf beizufügen.

$("input, select").change(function(){
    // Something changed
});

BEARBEITEN

Da Sie erwähnt haben, dass Sie dies nur für einen Klick benötigen, können Sie meinen ursprünglichen Code einfach so ändern:

$("input, select").click(function(){
    // A form element was clicked
});

EDIT # 2

Ok, Sie können ein Global festlegen, das festgelegt wird, sobald etwas wie folgt geändert wurde:

var FORM_HAS_CHANGED = false;

$('#mybutton').click(function() {
    if (FORM_HAS_CHANGED) {
        // The form has changed
    }
});

$("input, select").change(function(){
    FORM_HAS_CHANGED = true;
});
Joe D.
quelle
3

Wenn Sie sich die aktualisierte Frage ansehen, versuchen Sie etwas wie

$('input, textarea, select').each(function(){
    $(this).data("val", $(this).val());
});
$('#button').click(function() {
    $('input, textarea, select').each(function(){
        if($(this).data("val")!==$(this).val()) alert("Things Changed");
    });
});

Verwenden Sie für die ursprüngliche Frage so etwas wie

$('input').change(function() {
    alert("Things have changed!");
});
Pez Cuckow
quelle
Dies prüft nicht <textarea>oder <select>Elemente.
Nick Craver
Nach Ihrer Bearbeitung ... scheint dies eine Menge zusätzlicher Arbeit und Daten zu sein. Alles, was Sie brauchen, ist ein booleanSet auf true, wenn eine Änderung eintritt. Dies ist auch immer noch nicht formularspezifisch. Was wäre, wenn die Seite andere Formulare enthalten würde?
Nick Craver
+1 das ist gut, aber es braucht etwas Arbeit, binde es an form und setze init.
Anonym
Genau das habe ich mir gedacht :) (y) Du bist gerockt
RK Sharma
2
$('form :input').change(function() {
    // Something has changed
});
VoteyDisciple
quelle
2

Hier ist eine elegante Lösung.

Für jedes Eingabeelement im Formular gibt es eine versteckte Eigenschaft, mit der Sie bestimmen können, ob der Wert geändert wurde oder nicht. Jeder Eingabetyp hat einen eigenen Eigenschaftsnamen. Beispielsweise

  • für text/textareaes ist defaultValue
  • für selectes ist defaultSelect
  • denn checkbox/radioes ist defaultChecked

Hier ist das Beispiel.

function bindFormChange($form) {

  function touchButtons() {
    var
      changed_objects = [],
      $observable_buttons = $form.find('input[type="submit"], button[type="submit"], button[data-object="reset-form"]');

    changed_objects = $('input:text, input:checkbox, input:radio, textarea, select', $form).map(function () {
      var
        $input = $(this),
        changed = false;

      if ($input.is('input:text') || $input.is('textarea') ) {
        changed = (($input).prop('defaultValue') != $input.val());
      }
      if (!changed && $input.is('select') ) {
        changed = !$('option:selected', $input).prop('defaultSelected');
      }
      if (!changed && $input.is('input:checkbox') || $input.is('input:radio') ) {
        changed = (($input).prop('defaultChecked') != $input.is(':checked'));
      }
      if (changed) {
        return $input.attr('id');
      }

    }).toArray();

    if (changed_objects.length) {
      $observable_buttons.removeAttr('disabled')   
    } else {
      $observable_buttons.attr('disabled', 'disabled');
    }
  };
  touchButtons();

  $('input, textarea, select', $form).each(function () {
    var $input = $(this);

    $input.on('keyup change', function () {
      touchButtons();
    });
  });

};

Durchlaufen Sie jetzt einfach die Formulare auf der Seite und Sie sollten sehen, dass die Senden-Schaltflächen standardmäßig deaktiviert sind. Sie werden NUR aktiviert, wenn Sie tatsächlich einen Eingabewert im Formular ändern.

$('form').each(function () {
    bindFormChange($(this));
});

Die Implementierung als jQueryPlugin finden Sie hier https://github.com/kulbida/jmodifying

Entwickler
quelle
2
var formStr = JSON.stringify($("#form").serializeArray());
...
function Submit(){
   var newformStr = JSON.stringify($("#form").serializeArray());
   if (formStr != newformStr){
      ...
         formChangedfunct();
      ...
   }
   else {
      ...
         formUnchangedfunct();
      ...
   }
}
Péter Tajti
quelle
Ja, all die Jahre später benutze ich nicht einmal mehr jQuery. Beobachter und Bindungen jetzt den ganzen Weg! Schön für alle, die jQuery verwenden.
Mike
1

Wenn Sie die Antwort von Udi erweitern, wird nur die Formularübermittlung überprüft, nicht jede Eingabeänderung.

$(document).ready( function () {
  var form_data = $('#myform').serialize();
  $('#myform').submit(function () {
      if ( form_data == $(this).serialize() ) {
        alert('no change');
      } else {
        alert('change');
      }
   });
});
Ruby Racer
quelle
0

Zuerst würde ich Ihrem Formular eine versteckte Eingabe hinzufügen, um den Status des Formulars zu verfolgen. Dann würde ich dieses jQuery-Snippet verwenden, um den Wert der versteckten Eingabe festzulegen, wenn sich etwas im Formular ändert:

    $("form")
    .find("input")
    .change(function(){
        if ($("#hdnFormChanged").val() == "no")
        {
            $("#hdnFormChanged").val("yes");
        }
    });

Wenn Sie auf Ihre Schaltfläche klicken, können Sie den Status Ihrer versteckten Eingabe überprüfen:

$("#Button").click(function(){
    if($("#hdnFormChanged").val() == "yes")
    {
        // handler code here...
    }
});
JMP
quelle
0

$('form[name="your_form_name"] input, form[name="your_form_name"] select').click(function() {
  $("#result").html($(this).val());
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>Form "your_form_name"</h2>
<form name="your_form_name">
  <input type="text" name="one_a" id="one_a" value="AAAAAAAA" />
  <input type="text" name="one_b" id="one_b" value="BBBBBBBB" />
  <input type="text" name="one_c" id="one_c" value="CCCCCCCC" />
  <select name="one_d">
    <option value="111111">111111</option>
    <option value="222222">222222</option>
    <option value="333333">333333</option>
  </select>
</form>
<hr/>
<h2>Form "your_other_form_name"</h2>
<form name="your_other_form_name">
  <input type="text" name="two_a" id="two_a" value="DDDDDDDD" />
  <input type="text" name="two_b" id="two_b" value="EEEEEEEE" />
  <input type="text" name="two_c" id="two_c" value="FFFFFFFF" />
  <input type="text" name="two_d" id="two_d" value="GGGGGGGG" />
  <input type="text" name="two_e" id="two_f" value="HHHHHHHH" />
  <input type="text" name="two_f" id="two_e" value="IIIIIIII" />
  <select name="two_g">
    <option value="444444">444444</option>
    <option value="555555">555555</option>
    <option value="666666">666666</option>
  </select>
</form>
<h2>Result</h2>
<div id="result">
  <h2>Click on a field..</h2>
</div>

Zusätzlich zu der obigen Antwort von @ JoeD.

Wenn Sie Felder in einem bestimmten Formular (vorausgesetzt, es gibt mehr als ein Formular) als nur Felder als Ziel festlegen möchten, können Sie den folgenden Code verwenden:

$('form[name="your_form_name"] input, form[name="your_form_name"] select').click(function() {
    // A form element was clicked
});
Anjana Silva
quelle
Nur zu Ihrer Information, dies wird wahrscheinlich nicht das tun, was Sie wollen - es zielt auf die Eingabeelemente des Formulars "your_form_name" und alle Auswahlen im Dokument ab. Aus Leistungsgründen ist es auch immer besser, $ .fn.find zu verwenden, als nur auf $('form').find('input,select')
nachfolgende
@ user1167442 Wie wäre es, wenn wir mehr als ein Formular haben? Mein Beispiel ist eine Situation, in der eine Seite mehr als ein Formular enthält.
Anjana Silva
1
Aber dennoch - Ihr Beispiel findet alle Eingabeelemente, die untergeordnete Elemente des Formulars "your_form_name" sind, und findet dann alle Auswahlen, ob sie untergeordnete Elemente des Formulars "your_form_name" oder eines beliebigen Formulars sind. Ihr Beispiel funktioniert nicht für mehrere Formulare, es sei denn, Sie zielen nur auf die Auswahl dieser Formulare ab. Wenn Sie sich auf das Performance-Stück beziehen, ist es immer besser, $.fn.findschneller als gerade $.fn.filterauf untergeordnete Elemente zu verweisen, als absteigende Selektoren zu verwenden. vaughnroyko.com/the-real-scoop-on-jquery-find-performance
dgo
1
@ user1167442, du hast absolut recht. Ich habe die Tatsache übersehen, dass die Auswahl unabhängig von Ihrer Form als Ziel ausgewählt wird. Ich habe das korrigiert. Vielen Dank für den Hinweis. Prost!
Anjana Silva
0

Versuche dies:

<script>
var form_original_data = $("form").serialize(); 
var form_submit=false;
$('[type="submit"]').click(function() {
    form_submit=true;
});
window.onbeforeunload = function() {
    //console.log($("form").submit());
    if ($("form").serialize() != form_original_data && form_submit==false) {
        return "Do you really want to leave without saving?";
    }
};
</script>
Vinod Saraswat
quelle