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?


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.


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

});

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!');
});

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

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!");
});

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

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


2
var formStr = JSON.stringify($("#form").serializeArray());
...
function Submit(){
   var newformStr = JSON.stringify($("#form").serializeArray());
   if (formStr != newformStr){
      ...
         formChangedfunct();
      ...
   }
   else {
      ...
         formUnchangedfunct();
      ...
   }
}

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

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

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

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>
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.