Jak radzisz sobie ze zmianą formularza w jQuery?

82

Czy w jQuery istnieje prosty sposób sprawdzenia, czy JAKIEKOLWIEK elementy formularza uległy zmianie?

EDYCJA: Powinienem był dodać, że muszę tylko sprawdzić click()wydarzenie.

EDYCJA: Przepraszam, naprawdę powinienem był być bardziej szczegółowy! Powiedz, że mam formularz i mam przycisk z następującymi elementami:

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

Jak sprawdzić, czy formularz zmienił się od czasu załadowania?

mikrofon
źródło
Czy masz na myśli działanie jakiegoś innego skryptu zawartego na stronie, czy gdy tylko użytkownik wpisze jakiś tekst lub kliknie radio / pole wyboru?
FelipeAls
Powinienem był dodać, że muszę tylko sprawdzić zdarzenie click ()
mike

Odpowiedzi:

141

Możesz to zrobić:

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

To samojezdne do changeobsługi zdarzeń, aby wejść w formie, czy któryś z nich zmieni to wykorzystuje .data(), aby ustawić changedwartość true, a następnie po prostu sprawdzić na tej wartości na kliknięcie, to zakłada się, że #mybuttonjest wewnątrz formy (jeśli nie po prostu zastąpić $(this).closest('form')z $('#myForm')) ale możesz uczynić go jeszcze bardziej ogólnym, na przykład:

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

Odniesienia: zaktualizowane

Według jQuery jest to filtr do wybierania wszystkich kontrolek formularza.

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

Selektor: input zasadniczo wybiera wszystkie kontrolki formularza.

Nick Craver
źródło
6
Czy $('form :input')uwzględnia zaznaczanie, obszar tekstowy i inne typy danych wejściowych? czy jest to specyficzne dla tagu wejściowego?
Val
6
Popraw mnie, jeśli się mylę, ale wygląda na to, że ta metoda powie, że formularz został zmieniony, nawet jeśli ktoś wprowadzi zmianę, a następnie „cofnie” tę zmianę, ręcznie przywracając oryginalne wartości w formularzu. W tym przypadku forma naprawdę nie zmieniłaby się w odniesieniu do danych, ale ta metoda powiedziałaby, że tak.
paul
1
Dzięki, tak próbowałem (jest to wymienione w innej odpowiedzi), ale nie zadziałało. Wygląda na to, że istnieją pewne szczególne przypadki, które również powodują problemy z tą metodą. Obecnie pracuję z wtyczką - github.com/codedance/jquery.AreYouSure
paul
1
Dobre rozwiązanie w tym przypadku! Ale jeśli ktoś tutaj chce uzyskać stan zawartości formularza (np. „IsDirty”), możesz skorzystać z następującego rozwiązania: stackoverflow.com/a/26796840/665783
Jacob
1
@Nick Craver: Co zrobić, jeśli element formularza znajduje się poza znacznikiem formularza z atrybutem formularza jako identyfikatorem formularza. Przetestowałem obudowę, pech nie działa.
Mahantesh
50

Jeśli chcesz sprawdzić, czy dane formularza, które będą wysyłane na serwer, uległy zmianie, możesz serializować dane formularza podczas ładowania strony i porównać je z aktualnymi danymi formularza:

$(function() {

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

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

});
Udi
źródło
5
Świetnie, to najlepsze rozwiązanie tutaj. Dzięki.
Anonimowy
3
Kiedyś użyłem tej metody i stała się bardzo powolna, gdy forma stała się większa. To dobra metoda w przypadku małych form, ale nie jest to dobra metoda w przypadku dużych form.
mkdevoogd
masz na myśli formularze z plikami w nich?
Udi
1
To dobrze, ale byłoby lepiej, gdyby zamiast sprawdzać za każdym razem, gdy zmienia się kontrola, bezpośrednio sprawdzać, kiedy formularz ma zostać przesłany
Ruby Racer
2
Jest to znacznie lepsze, więc możesz wyzwolić przyciski z powrotem do wyłączonych, na przykład „usuń”
EliuX,
31

Proste rozwiązanie w czasie rzeczywistym:

$('form').on('keyup change paste', 'input, select, textarea', function(){
    console.log('Form changed!');
});
Marcio Mazzucato
źródło
1
Bardzo dobre rozwiązanie. Nadaje się do sprawdzania poprawności podczas pisania.
Bijan
1
Najlepsze rozwiązanie dla mnie! Wielkie dzięki.
Ivan
2
Rozważ użycie 'input'zamiast 'keyup change'obsługi wklejania prawym przyciskiem myszy, chyba że potrzebujesz obsługi starszych przeglądarek.
TrueWill
10

Możesz użyć wielu selektorów, aby dołączyć wywołanie zwrotne do zdarzenia zmiany dla dowolnego elementu formularza.

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

EDYTOWAĆ

Ponieważ wspomniałeś, że potrzebujesz tego tylko do kliknięcia, możesz po prostu zmodyfikować mój oryginalny kod do tego:

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

EDYCJA # 2

Ok, możesz ustawić globalny, który zostanie ustawiony, gdy coś zostanie zmienione w ten sposób:

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.
źródło
3

Patrząc na zaktualizowane pytanie, spróbuj czegoś takiego

$('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");
    });
});

W przypadku oryginalnego pytania użyj czegoś w rodzaju

$('input').change(function() {
    alert("Things have changed!");
});
Pez Cuckow
źródło
To nie sprawdza <textarea>ani <select>elementów.
Nick Craver
Po edycji ... wydaje się, że jest to dużo dodatkowej pracy i przenoszenia danych, wystarczy, że booleanustawisz wartość true, gdy nastąpi zmiana. Ponadto nadal nie jest to specyficzne dla formularza, a co by było, gdyby na stronie były inne formularze?
Nick Craver
+1 to jest dobre, ale wymaga trochę pracy, powiąż go z formą i ustaw init.
Anonimowy
tak właśnie myślałem :) (y) kołysałeś
RK Sharma
2
$('form :input').change(function() {
    // Something has changed
});
VoteyDisciple
źródło
2

Oto eleganckie rozwiązanie.

Dla każdego elementu wejściowego w formularzu istnieje ukryta właściwość, której można użyć do określenia, czy wartość została zmieniona. Każdy typ danych wejściowych ma własną nazwę właściwości. Na przykład

  • bo text/textareato defaultValue
  • bo selectto jest domyślne Wybierz
  • bo checkbox/radioto jest defaultChecked

Oto przykład.

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

};

Teraz po prostu przejrzyj formularze na stronie i powinieneś zobaczyć przyciski przesyłania wyłączone domyślnie i zostaną one aktywowane TYLKO, jeśli rzeczywiście zmienisz jakąś wartość wejściową w formularzu.

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

Implementacja jako jQuerywtyczka jest tutaj https://github.com/kulbida/jmodifiable

Deweloper
źródło
2
var formStr = JSON.stringify($("#form").serializeArray());
...
function Submit(){
   var newformStr = JSON.stringify($("#form").serializeArray());
   if (formStr != newformStr){
      ...
         formChangedfunct();
      ...
   }
   else {
      ...
         formUnchangedfunct();
      ...
   }
}
Péter Tajti
źródło
Tak, przez te wszystkie lata później nawet nie używam jQuery. Obserwatorzy i powiązania do końca teraz! Miło jednak dla każdego, kto używa jQuery.
mike
1

Rozszerzając odpowiedź Udi, sprawdza to tylko przesłanie formularza, a nie każdą zmianę danych wejściowych.

$(document).ready( function () {
  var form_data = $('#myform').serialize();
  $('#myform').submit(function () {
      if ( form_data == $(this).serialize() ) {
        alert('no change');
      } else {
        alert('change');
      }
   });
});
Ruby Racer
źródło
0

Najpierw dodam do formularza ukryte dane wejściowe, aby śledzić stan formularza. Następnie użyłbym tego fragmentu kodu jQuery, aby ustawić wartość ukrytych danych wejściowych, gdy coś w formularzu się zmieni:

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

Po kliknięciu przycisku możesz sprawdzić stan ukrytych danych wejściowych:

$("#Button").click(function(){
    if($("#hdnFormChanged").val() == "yes")
    {
        // handler code here...
    }
});
JMP
źródło
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>

Oprócz powyższej odpowiedzi @ JoeD.

Jeśli chcesz kierować reklamy na pola w określonym formularzu (zakładając, że istnieje więcej niż jeden formularz) niż tylko na pola, możesz użyć następującego kodu:

$('form[name="your_form_name"] input, form[name="your_form_name"] select').click(function() {
    // A form element was clicked
});
Anjana Silva
źródło
Do Twojej wiadomości, to prawdopodobnie nie zrobi tego, co chcesz - dotyczy elementów wejściowych formularza "twoja_nazwa_formy" i wszystkich zaznaczeń w dokumencie. Ponadto, ze względu na wydajność, zawsze lepiej jest używać $ .fn.find niż tylko kierować na selektory $('form').find('input,select')
potomne
@ user1167442 A jeśli mamy więcej niż jeden formularz? Mój przykład dotyczy sytuacji, w której na jednej stronie jest więcej niż jeden formularz.
Anjana Silva
1
Ale mimo wszystko - Twój przykład znajdzie wszystkie elementy wejściowe, które są elementami potomnymi formularza „twoja_nazwa_formy”, a następnie znajdzie wszystkie zaznaczenia, czy są one elementami podrzędnymi „twoja_nazwa_formy”, czy w ogóle. Twój przykład nie zadziała dla wielu formularzy, chyba że kierujesz tylko wybrane formularze. Ponadto, jeśli odnosisz się do utworu wykonawczego, zawsze lepiej jest używać $.fn.find- szybciej niż równo $.fn.filter- odwoływać się do dzieci, zamiast używać selektorów potomnych. vaughnroyko.com/the-real-scoop-on-jquery-find-performance
dgo
1
@ user1167442, masz całkowitą rację. Brakowało mi faktu, że celem kierowania jest funkcja Select, niezależnie od tego, w jakiej jesteś formie. Poprawiłem to. Bardzo dziękuję za zwrócenie uwagi. Twoje zdrowie!
Anjana Silva
0

Spróbuj tego:

<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
źródło