[javascript] HTML 양식이 편집되었는지 감지하는 일반적인 방법

탭 HTML 양식이 있습니다. 한 탭에서 다른 탭으로 이동하면 데이터가 변경되지 않아도 현재 탭의 데이터가 DB에 유지됩니다.

양식이 편집 된 경우에만 지속성 호출을 만들고 싶습니다. 양식에는 모든 종류의 컨트롤이 포함될 수 있습니다. 일부 텍스트를 입력하여 양식을 더럽히는 것은 아니지만 달력 컨트롤에서 날짜를 선택하는 것도 적합합니다.

이를 달성하는 한 가지 방법은 기본적으로 양식을 읽기 전용 모드로 표시하고 ‘편집’버튼을 갖는 것이며 사용자가 편집 버튼을 클릭하면 DB에 대한 호출이 이루어집니다 (데이터 수정 여부에 관계없이 다시 한 번) . 이것은 현재 존재하는 것보다 더 나은 개선입니다).

컨트롤 값이 수정되었는지 확인하는 일반 자바 스크립트 함수를 작성하는 방법을 알고 싶습니다.



답변

순수한 자바 스크립트에서 이것은 쉬운 작업이 아니지만 jQuery를 사용하면 매우 쉽게 할 수 있습니다.

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

그런 다음 저장하기 전에 변경되었는지 확인할 수 있습니다.

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

위의 예에서 양식에는 “myform”과 동일한 ID가 있습니다.

여러 형태로 필요한 경우 쉽게 플러그인으로 전환 할 수 있습니다.

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

그런 다음 간단히 말할 수 있습니다.

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

양식이 변경되었는지 확인하십시오.

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


답변

JQuery가 문제가 아닌 경우. Google의 빠른 검색에서 MD5 및 SHA1 해시 알고리즘의 Javascript 구현을 찾았습니다. 원하는 경우 모든 양식 입력을 연결하고 해시 한 다음 해당 값을 메모리에 저장할 수 있습니다. 사용자가 완료되면. 모든 값을 연결하고 다시 해시하십시오. 2 개의 해시를 비교하십시오. 동일하면 사용자가 양식 필드를 변경하지 않은 것입니다. 서로 다르면 무언가 편집 된 것이므로 지속성 코드를 호출해야합니다.


답변

질문이 올바른지 확실하지 않지만 addEventListener는 어떻습니까? IE8 지원에 너무 신경 쓰지 않는다면 괜찮을 것입니다. 다음 코드가 저에게 효과적입니다.

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

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


답변

이를 달성하는 또 다른 방법은 양식을 직렬화하는 것입니다.

$(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>


답변

다음은 내가 한 방법입니다 (jQuery를 사용하지 않고).

제 경우에는 검사를 트리거 한 요소이므로 항상 변경 될 것이기 때문에 하나의 특정 양식 요소가 계산되지 않기를 원했습니다. 예외적 인 요소의 이름은 ‘reporting_period’이며 ‘hasFormChanged ()’함수에 하드 코딩되어 있습니다.

테스트하려면 요소가 “changeReportingPeriod ()”함수를 호출하도록 만드십시오. 아마도 다른 이름을 지정하고 싶을 것입니다.

중요 : 값이 원래 값으로 설정되면 setInitialValues ​​()를 호출해야합니다 (일반적으로 페이지로드시, 제 경우에는 아님).

참고 : 저는 이것이 우아한 솔루션이라고 주장하지 않습니다. 사실 저는 우아한 JavaScript 솔루션을 믿지 않습니다. JavaScript에서 개인적으로 강조하는 것은 구조적 우아함이 아니라 가독성에 있습니다 (JavaScript에서 가능했던 것처럼). JavaScript를 작성할 때 파일 크기는 전혀 신경 쓰지 않습니다. 이것이 gzip의 목적이기 때문이며,보다 간결한 JavaScript 코드를 작성하려고하면 항상 유지 관리에 참을 수없는 문제가 발생합니다. 나는 사과하지 않으며, 후회하지도 않으며, 토론을 거부합니다. JavaScript입니다. 죄송합니다. 게시를 귀찮게해야한다고 스스로 확신하기 위해이 사실을 분명히해야했습니다. 행복하세요! 🙂


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



답변

jQuery없이 네이티브 JavaScript에서 양식 변경을 쉽게 감지 할 수 있습니다.

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()페이지의 수명주기 동안 여러 번 안전하게 호출 할 수 있습니다 . JSBin에서 테스트를 참조하세요.


최신 화살표 / 배열 기능을 지원하지 않는 이전 브라우저의 경우 :

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


답변

다음은 FormData()API를 사용하여 생성, 업데이트 및 삭제 된 양식 항목을 감지 하는 네이티브 JavaScript의 polyfill 메서드 데모입니다 . 다음을 사용하여 변경된 사항이 있는지 확인하고 다음을 사용하여 HTMLFormElement#isChanged재설정 양식의 차이점을 포함하는 객체를 가져올 수 있습니다 HTMLFormElement#changes(입력 이름에 의해 마스크되지 않는다고 가정).

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>