HTML formunun düzenlenip düzenlenmediğini tespit etmenin genel yolu


95

Sekmeli bir html formum var. Bir sekmeden diğerine geçildiğinde, verilerde herhangi bir değişiklik olmasa bile geçerli sekmenin verileri (DB'de) saklanır.

Kalıcılık çağrısını yalnızca form düzenlenmişse yapmak istiyorum. Form her türlü kontrolü içerebilir. Formu kirletmek, bir metin yazarak olmak zorunda değildir, ancak bir takvim denetiminde bir tarih seçmek de uygun olacaktır.

Bunu başarmanın bir yolu, formu varsayılan olarak salt okunur modda görüntülemek ve bir 'Düzenle' düğmesine sahip olmaktır ve kullanıcı düzenleme düğmesini tıklarsa DB'ye çağrı yapılır (verilerin değiştirilip değiştirilmediğine bakılmaksızın bir kez daha Bu, şu anda mevcut olana göre daha iyi bir gelişmedir).

Kontrol değerlerinden herhangi birinin değiştirilip değiştirilmediğini kontrol edecek genel bir javascript işlevinin nasıl yazılacağını bilmek istiyorum.


Bir ilginç çözüm SitePoint Craig Buckler gönderildi. Özellikle ilgi çekici olan çözüm jQuery'ye dayanmaz ve çapraz tarayıcı uyumludur.
MagicAndi

Yanıtlar:


160

Saf javascript'te bu kolay bir iş olmaz, ancak jQuery bunu yapmayı çok kolaylaştırır:

$("#myform :input").change(function() {
   $("#myform").data("changed",true);
});

Ardından kaydetmeden önce, değiştirilip değiştirilmediğini kontrol edebilirsiniz:

if ($("#myform").data("changed")) {
   // submit the form
}

Yukarıdaki örnekte, formun "myform" a eşit bir kimliği vardır.

Buna birçok biçimde ihtiyacınız varsa, onu kolayca bir eklentiye dönüştürebilirsiniz:

$.fn.extend({
 trackChanges: function() {
   $(":input",this).change(function() {
      $(this.form).data("changed", true);
   });
 }
 ,
 isChanged: function() { 
   return this.data("changed"); 
 }
});

O zaman basitçe şunu söyleyebilirsin:

$("#myform").trackChanges();

ve bir formun değişip değişmediğini kontrol edin:

if ($("#myform").isChanged()) {
   // ...
}

13
Bu güzel ve basit. Ancak, kullanıcı bir form girişini değiştirir ve ardından değişikliği geri alırsa (örneğin, bir onay kutusunu iki kez tıklatarak), bu durumda form değiştirilmiş olarak kabul edilecektir. Bunun kabul edilebilir olup olmadığı elbette içeriğe bağlıdır. Alternatif için stackoverflow.com/questions/10311663/…
jlh

1
canlı girişler için bazı değişiklikler gerekiyor trackChanges: function () { $(document).on('change', $(this).find(':input'), function (e) { var el = $(e.target); $(el).closest('form').data("changed", true); });
Dimmduh

36

JQuery'nin söz konusu olmaması durumunda. Google'da hızlı bir arama, MD5 ve SHA1 karma algoritmalarının Javascript uygulamalarını buldu. İsterseniz, tüm form girişlerini birleştirebilir ve hashing uygulayabilir, ardından bu değeri bellekte depolayabilirsiniz. Kullanıcı bittiğinde. Tüm değerleri ve hash'i tekrar birleştirin. 2 karmayı karşılaştırın. Aynı iseler, kullanıcı herhangi bir form alanını değiştirmemiştir. Farklılarsa, bir şey düzenlenmiştir ve kalıcılık kodunuzu aramanız gerekir.


2
Bu soru için beklediğim bu, kütüphane var mı?
Hamedz

Tüm alanları birleştirip hashing uygulamasaydınız sonuç aynı olmaz mıydı?
ashleedawg

Evet, ancak verilerin kendisi hash'den daha büyük olabilir.
JRG

26

Sorunuzu doğru anladığımdan emin değilim, peki ya addEventListener? IE8 desteğini fazla önemsemiyorsanız, bu iyi olacaktır. Aşağıdaki kod benim için çalışıyor:

var form = document.getElementById("myForm");

form.addEventListener("input", function () {
    console.log("Form has changed!");
});

ihtiyaçlarım için mükemmel
Kutsama

8

Bunu başarmanın bir başka yolu da formu seri hale getirmektir:

$(function() {
    var $form = $('form');
    var initialState = $form.serialize();
    
    $form.submit(function (e) {
      if (initialState === $form.serialize()) {
        console.log('Form is unchanged!');
      } else {
        console.log('Form has changed!');
      }
      e.preventDefault();
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
Field 1: <input type="text" name="field_1" value="My value 1"> <br>
Field 2: <input type="text" name="field_2" value="My value 2"> <br>
Check: <input type="checkbox" name="field_3" value="1"><br>
<input type="submit">
</form>


Düşünme şeklinizi seviyorum, özellikle jQuery'yi çıkarırsanız ve bunu vanilya JavaScript ile yaparsanız. Sorunun jQuery'nin mevcut olduğunu varsaydığının farkındayım, ancak yorumlardaki uyarılara benzer şekilde daha geniş çapta uygulanabilir bir çözüme sahip olmamak için hiçbir neden yok .
ruffin

4

İşte nasıl yaptım (jQuery kullanmadan).

Benim durumumda, belirli bir form öğesinin sayılmamasını istedim, çünkü denetimi tetikleyen öğeydi ve bu nedenle her zaman değişecek. İstisnai öğe, 'raporlama_dönemi' olarak adlandırılır ve 'hasFormChanged ()' işlevinde sabit kodlanmıştır.

Test etmek için, bir elemanın "changeReportingPeriod ()" işlevini çağırmasını sağlayın, muhtemelen başka bir ad vermek isteyeceksiniz.

ÖNEMLİ: Değerler orijinal değerlerine ayarlandığında setInitialValues ​​() 'i çağırmalısınız (tipik olarak sayfa yüklenirken, ama benim durumumda değil).

NOT: Bunun zarif bir çözüm olduğunu iddia etmiyorum, aslında zarif JavaScript çözümlerine inanmıyorum. JavaScript'teki kişisel vurgum, yapısal zarafet değil (JavaScript'te mümkünmüş gibi) okunabilirlik üzerinedir. JavaScript yazarken dosya boyutuyla hiç ilgilenmiyorum çünkü gzip bunun içindir ve daha kompakt JavaScript kodu yazmaya çalışmak her zaman bakımla dayanılmaz sorunlara yol açar. Özür dilemiyorum, pişmanlık duymuyorum ve bunu tartışmayı reddediyorum. JavaScript. Üzgünüm, kendimi gönderi paylaşmam gerektiğine ikna etmek için bunu netleştirmek zorundaydım. Mutlu ol! :)


    var initial_values = new Array();

    // Gets all form elements from the entire document.
    function getAllFormElements() {
        // Return variable.
        var all_form_elements = Array();

        // The form.
        var form_activity_report = document.getElementById('form_activity_report');

        // Different types of form elements.
        var inputs = form_activity_report.getElementsByTagName('input');
        var textareas = form_activity_report.getElementsByTagName('textarea');
        var selects = form_activity_report.getElementsByTagName('select');

        // We do it this way because we want to return an Array, not a NodeList.
        var i;
        for (i = 0; i < inputs.length; i++) {
            all_form_elements.push(inputs[i]);
        }
        for (i = 0; i < textareas.length; i++) {
            all_form_elements.push(textareas[i]);
        }
        for (i = 0; i < selects.length; i++) {
            all_form_elements.push(selects[i]);
        }

        return all_form_elements;
    }

    // Sets the initial values of every form element.
    function setInitialFormValues() {
        var inputs = getAllFormElements();
        for (var i = 0; i < inputs.length; i++) {
            initial_values.push(inputs[i].value);
        }
    }

    function hasFormChanged() {
        var has_changed = false;
        var elements = getAllFormElements();

        for (var i = 0; i < elements.length; i++) {
            if (elements[i].id != 'reporting_period' && elements[i].value != initial_values[i]) {
                has_changed = true;
                break;
            }
        }

        return has_changed;
    }

    function changeReportingPeriod() {
        alert(hasFormChanged());
    }



3

Form değişiklikleri, jQuery olmadan yerel JavaScript'te kolayca tespit edilebilir:

function initChangeDetection(form) {
  Array.from(form).forEach(el => el.dataset.origValue = el.value);
}
function formHasChanges(form) {
  return Array.from(form).some(el => 'origValue' in el.dataset && el.dataset.origValue !== el.value);
}


initChangeDetection()sayfanızın yaşam döngüsü boyunca birden çok kez güvenle çağrılabilir: Bkz. JSBin'de Test Etme


Daha yeni ok / dizi işlevlerini desteklemeyen eski tarayıcılar için:

function initChangeDetection(form) {
  for (var i=0; i<form.length; i++) {
    var el = form[i];
    el.dataset.origValue = el.value;
  }
}
function formHasChanges(form) {
  for (var i=0; i<form.length; i++) {
    var el = form[i];
    if ('origValue' in el.dataset && el.dataset.origValue !== el.value) {
      return true;
    }
  }
  return false;
}


Formunuzu görebilmemiz için formunuzu JSBin'e veya Gist'e gönderebilir misiniz?
AnthumChris

benim hatam, jquery ile formu seçtim, örneğinizdeki gibi JS ile değil. Serileştirme aşırı yüklemesi olmadan güzel ve temiz bir js çözümüdür. Teşekkür ederim!
Rich Stone

2

Burada FormData(), oluşturulan, güncellenen ve silinen form girişlerini algılamak için API kullanan yerel JavaScript'te bir çoklu doldurma yöntemi demosu bulunmaktadır . Kullanarak herhangi bir şeyin değiştirilip değiştirilmediğini kontrol edebilir HTMLFormElement#isChangedve HTMLFormElement#changes(bir giriş adı ile maskelenmedikleri varsayılarak) sıfırlama formundan farklılıkları içeren bir nesne alabilirsiniz :

Object.defineProperties(HTMLFormElement.prototype, {
  isChanged: {
    configurable: true,
    get: function isChanged () {
      'use strict'

      var thisData = new FormData(this)
      var that = this.cloneNode(true)

      // avoid masking: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/reset
      HTMLFormElement.prototype.reset.call(that)

      var thatData = new FormData(that)

      const theseKeys = Array.from(thisData.keys())
      const thoseKeys = Array.from(thatData.keys())

      if (theseKeys.length !== thoseKeys.length) {
        return true
      }

      const allKeys = new Set(theseKeys.concat(thoseKeys))

      function unequal (value, index) {
        return value !== this[index]
      }

      for (const key of theseKeys) {
        const theseValues = thisData.getAll(key)
        const thoseValues = thatData.getAll(key)

        if (theseValues.length !== thoseValues.length) {
          return true
        }

        if (theseValues.some(unequal, thoseValues)) {
          return true
        }
      }

      return false
    }
  },
  changes: {
    configurable: true,
    get: function changes () {
      'use strict'

      var thisData = new FormData(this)
      var that = this.cloneNode(true)

      // avoid masking: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/reset
      HTMLFormElement.prototype.reset.call(that)

      var thatData = new FormData(that)

      const theseKeys = Array.from(thisData.keys())
      const thoseKeys = Array.from(thatData.keys())

      const created = new FormData()
      const deleted = new FormData()
      const updated = new FormData()

      const allKeys = new Set(theseKeys.concat(thoseKeys))

      function unequal (value, index) {
        return value !== this[index]
      }

      for (const key of allKeys) {
        const theseValues = thisData.getAll(key)
        const thoseValues = thatData.getAll(key)

        const createdValues = theseValues.slice(thoseValues.length)
        const deletedValues = thoseValues.slice(theseValues.length)

        const minLength = Math.min(theseValues.length, thoseValues.length)

        const updatedValues = theseValues.slice(0, minLength).filter(unequal, thoseValues)

        function append (value) {
          this.append(key, value)
        }

        createdValues.forEach(append, created)
        deletedValues.forEach(append, deleted)
        updatedValues.forEach(append, updated)
      }

      return {
        created: Array.from(created),
        deleted: Array.from(deleted),
        updated: Array.from(updated)
      }
    }
  }
})

document.querySelector('[value="Check"]').addEventListener('click', function () {
  if (this.form.isChanged) {
    console.log(this.form.changes)
  } else {
    console.log('unchanged')
  }
})
<form>
  <div>
    <label for="name">Text Input:</label>
    <input type="text" name="name" id="name" value="" tabindex="1" />
  </div>

  <div>
    <h4>Radio Button Choice</h4>

    <label for="radio-choice-1">Choice 1</label>
    <input type="radio" name="radio-choice-1" id="radio-choice-1" tabindex="2" value="choice-1" />

    <label for="radio-choice-2">Choice 2</label>
    <input type="radio" name="radio-choice-2" id="radio-choice-2" tabindex="3" value="choice-2" />
  </div>

  <div>
    <label for="select-choice">Select Dropdown Choice:</label>
    <select name="select-choice" id="select-choice">
      <option value="Choice 1">Choice 1</option>
      <option value="Choice 2">Choice 2</option>
      <option value="Choice 3">Choice 3</option>
    </select>
  </div>

  <div>
    <label for="textarea">Textarea:</label>
    <textarea cols="40" rows="8" name="textarea" id="textarea"></textarea>
  </div>

  <div>
    <label for="checkbox">Checkbox:</label>
    <input type="checkbox" name="checkbox" id="checkbox" />
  </div>

  <div>
    <input type="button" value="Check" />
  </div>
</form>

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.