developer tip

저장되지 않은 변경 사항 감지

optionbox 2020. 9. 9. 07:57
반응형

저장되지 않은 변경 사항 감지


ASP .Net 응용 프로그램에서 "저장되지 않은 변경 사항"프롬프트를 구현해야합니다. 사용자가 웹 양식에서 컨트롤을 수정하고 저장하기 전에 다른 곳으로 이동하려고하면 저장되지 않은 변경 사항이 있음을 경고하는 메시지가 나타나고 취소하고 현재 페이지에 머무를 수있는 옵션을 제공해야합니다. 사용자가 컨트롤을 터치하지 않은 경우 프롬프트가 표시되지 않아야합니다.

이상적으로는 이것을 JavaScript로 구현하고 싶지만 자체 코드를 롤링하기 전에이를 달성하기위한 기존 프레임 워크 또는 권장 디자인 패턴이 있습니까? 이상적으로는 최소한의 변경으로 여러 페이지에서 쉽게 재사용 할 수있는 것을 원합니다.


jQuery 사용 :

var _isDirty = false;
$("input[type='text']").change(function(){
  _isDirty = true;
});
// replicate for other input types and selects

필요에 따라 onunload/ onbeforeunload메소드 와 결합하십시오 .

주석에서 다음은 코드를 복제하지 않고 모든 입력 필드를 참조합니다.

$(':input').change(function () {

사용 $(":input")은 모든 입력, 텍스트 영역, 선택 및 단추 요소를 나타냅니다.


퍼즐의 한 조각 :

/**
 * Determines if a form is dirty by comparing the current value of each element
 * with its default value.
 *
 * @param {Form} form the form to be checked.
 * @return {Boolean} <code>true</code> if the form is dirty, <code>false</code>
 *                   otherwise.
 */
function formIsDirty(form) {
  for (var i = 0; i < form.elements.length; i++) {
    var element = form.elements[i];
    var type = element.type;
    if (type == "checkbox" || type == "radio") {
      if (element.checked != element.defaultChecked) {
        return true;
      }
    }
    else if (type == "hidden" || type == "password" ||
             type == "text" || type == "textarea") {
      if (element.value != element.defaultValue) {
        return true;
      }
    }
    else if (type == "select-one" || type == "select-multiple") {
      for (var j = 0; j < element.options.length; j++) {
        if (element.options[j].selected !=
            element.options[j].defaultSelected) {
          return true;
        }
      }
    }
  }
  return false;
}

그리고 다른 :

window.onbeforeunload = function(e) {
  e = e || window.event;  
  if (formIsDirty(document.forms["someForm"])) {
    // For IE and Firefox
    if (e) {
      e.returnValue = "You have unsaved changes.";
    }
    // For Safari
    return "You have unsaved changes.";
  }
};

모두 마무리하면 무엇을 얻습니까?

var confirmExitIfModified = (function() {
  function formIsDirty(form) {
    // ...as above
  }

  return function(form, message) {
    window.onbeforeunload = function(e) {
      e = e || window.event;
      if (formIsDirty(document.forms[form])) {
        // For IE and Firefox
        if (e) {
          e.returnValue = message;
        }
        // For Safari
        return message;
      }
    };
  };
})();

confirmExitIfModified("someForm", "You have unsaved changes.");

의 이벤트 등록 beforeunload을 사용 하도록 이벤트 처리기 의 등록을 변경하고 싶을 수도 있습니다 LIBRARY_OF_CHOICE.


.aspx 페이지에서 양식 정보가 "더러운"지 여부를 알려주는 Javascript 함수가 필요합니다.

<script language="javascript">
    var isDirty = false;

    function setDirty() {
        isDirty = true;
    }

    function checkSave() {
        var sSave;
        if (isDirty == true) {
            sSave = window.confirm("You have some changes that have not been saved. Click OK to save now or CANCEL to continue without saving.");
            if (sSave == true) {
                document.getElementById('__EVENTTARGET').value = 'btnSubmit';
                document.getElementById('__EVENTARGUMENT').value = 'Click';  
                window.document.formName.submit();
            } else {
                 return true;
            }
        }
    }
</script>
<body class="StandardBody" onunload="checkSave()">

코드 숨김에서 입력 필드에 트리거를 추가하고 제출 / 취소 버튼에 대한 재설정을 추가합니다 ....

btnSubmit.Attributes.Add("onclick", "isDirty = 0;");
btnCancel.Attributes.Add("onclick", "isDirty = 0;");
txtName.Attributes.Add("onchange", "setDirty();");
txtAddress.Attributes.Add("onchange", "setDirty();");
//etc..

다음은 브라우저의 onbeforeunload 함수와 jquery를 사용하여 onchange 이벤트를 캡처합니다. IT는 또한 변경이 발생했음을 나타내는 플래그를 재설정하기 위해 제출 또는 재설정 버튼을 찾습니다.

dataChanged = 0;     // global variable flags unsaved changes      

function bindForChange(){    
     $('input,checkbox,textarea,radio,select').bind('change',function(event) { dataChanged = 1})
     $(':reset,:submit').bind('click',function(event) { dataChanged = 0 })
}


function askConfirm(){  
    if (dataChanged){ 
        return "You have some unsaved changes.  Press OK to continue without saving." 
    }
}

window.onbeforeunload = askConfirm;
window.onload = bindForChange;

모두 답장 해 주셔서 감사합니다. 결국 JQuery와 Protect-Data 플러그인을 사용하여 솔루션을 구현 했습니다. 이를 통해 페이지의 모든 컨트롤에 모니터링을 자동으로 적용 할 수 있습니다.

그러나 특히 ASP .Net 응용 프로그램을 다룰 때 몇 가지주의 사항이 있습니다.

  • 사용자가 취소 옵션을 선택하면 doPostBack 함수가 JavaScript 오류를 발생시킵니다. 그것을 억제하기 위해 doPostBack 내에서 .submit 호출 주위에 try-catch를 수동으로 넣어야했습니다.

  • 일부 페이지에서 사용자는 동일한 페이지에 대한 포스트 백을 수행하지만 저장이 아닌 작업을 수행 할 수 있습니다. 이로 인해 JavaScript 로직이 재설정되므로 포스트 백 후 변경된 사항이 없다고 생각합니다. 페이지와 함께 다시 게시되는 숨겨진 텍스트 상자를 구현해야했으며 데이터가 더러워 졌는지 여부를 나타내는 간단한 부울 값을 유지하는 데 사용됩니다. 이것은 포스트 백에서 지속됩니다.

  • 저장 버튼과 같은 페이지의 일부 포스트 백이 대화 상자를 트리거하지 않도록 할 수 있습니다. 이 경우 JQuery를 사용하여 window.onbeforeunload를 null로 설정하는 OnClick 함수를 추가 할 수 있습니다.

바라건대 이것은 비슷한 것을 구현해야하는 다른 사람에게 도움이되기를 바랍니다.


다음 솔루션은 프로토 타입에 대해 작동합니다 (FF, IE 6 및 Safari에서 테스트 됨). 일반 양식 옵저버 (form : changed 양식의 필드가 수정되면 변경됨)를 사용하며 다른 항목에도 사용할 수 있습니다.

/* use this function to announce changes from your own scripts/event handlers.
 * Example: onClick="makeDirty($(this).up('form'));"
 */
function makeDirty(form) {
    form.fire("form:changed");
}

function handleChange(form, event) {
    makeDirty(form);
}

/* generic form observer, ensure that form:changed is being fired whenever
 * a field is being changed in that particular for
 */
function setupFormChangeObserver(form) {
    var handler = handleChange.curry(form);

    form.getElements().each(function (element) {
        element.observe("change", handler);
    });
}

/* installs a form protector to a form marked with class 'protectForm' */
function setupProtectForm() {
    var form = $$("form.protectForm").first();

    /* abort if no form */
    if (!form) return;

    setupFormChangeObserver(form);

    var dirty = false;
    form.observe("form:changed", function(event) {
        dirty = true;
    });

    /* submitting the form makes the form clean again */
    form.observe("submit", function(event) {
        dirty = false;
    });

    /* unfortunatly a propper event handler doesn't appear to work with IE and Safari */
    window.onbeforeunload = function(event) {
        if (dirty) {
            return "There are unsaved changes, they will be lost if you leave now.";
        }
    };
}

document.observe("dom:loaded", setupProtectForm);

다음은 간단한 javascript / jquery 솔루션입니다. 사용자에 의한 "실행 취소"를 설명하고 응용 프로그램의 용이성을 위해 함수 내에 캡슐화되며 제출시 잘못 실행되지 않습니다. 함수를 호출하고 양식의 ID를 전달하십시오.

이 함수는 페이지가로드 될 때 한 번, 사용자가 페이지를 떠나기 전에 양식을 직렬화합니다. 두 양식 상태가 다른 경우 프롬프트가 표시됩니다.

시도해보세요 : http://jsfiddle.net/skibulk/Ydt7Y/

function formUnloadPrompt(formSelector) {
    var formA = $(formSelector).serialize(), formB, formSubmit = false;

    // Detect Form Submit
    $(formSelector).submit( function(){
        formSubmit = true;
    });

    // Handle Form Unload    
    window.onbeforeunload = function(){
        if (formSubmit) return;
        formB = $(formSelector).serialize();
        if (formA != formB) return "Your changes have not been saved.";
    };
}

$(function(){
    formUnloadPrompt('form');
});

주어진 페이지에서 여러 양식을 지원하는 일반 솔루션 ( 프로젝트에 복사하여 붙여 넣기 만하면 됨 )

$(document).ready(function() {
    $('form :input').change(function() {
        $(this).closest('form').addClass('form-dirty');
    });

    $(window).bind('beforeunload', function() {
        if($('form:not(.ignore-changes).form-dirty').length > 0) {
            return 'You have unsaved changes, are you sure you want to discard them?';
        }
    });

    $('form').bind('submit',function() {
        $(this).closest('form').removeClass('form-dirty');
        return true;
    });
});

참고 :이 솔루션은 다른 솔루션과 결합되어 일반적인 통합 솔루션을 만듭니다.

풍모:

  • 앱에 복사하여 붙여 넣기 만하면됩니다.
  • 여러 양식을 지원합니다.
  • 액션은 "form-dirty"클래스이기 때문에 스타일을 지정하거나 더티 폼을 만들 수 있습니다.
  • 'ignore-changes'클래스를 추가하여 일부 양식을 제외 할 수 있습니다.

최근에 dirtyForms 라는 오픈 소스 jQuery 플러그인에 기여했습니다 .

플러그인은 동적으로 추가 된 HTML과 함께 작동하도록 설계되었으며, 여러 양식을 지원하고, 거의 모든 대화 프레임 워크를 지원할 수 있으며, 대화 상자를 언로드하기 전에 브라우저로 폴백하고, 사용자 정의 편집기에서 더티 상태를 가져 오는 것을 지원하는 플러그 형 도우미 프레임 워크가 있습니다 (tinyMCE 플러그인이 포함됨). , iFrame 내에서 작동하며 더티 상태를 마음대로 설정하거나 재설정 할 수 있습니다.

https://github.com/snikch/jquery.dirtyforms


Detect form changes with using jQuery is very simple:

var formInitVal = $('#formId').serialize(); // detect form init value after form is displayed

// check for form changes
if ($('#formId').serialize() != formInitVal) {
    // show confirmation alert
}

I expanded on Slace's suggestion above, to include most editable elements and also excluding certain elements (with a CSS style called "srSearch" here) from causing the dirty flag to be set.

<script type="text/javascript">
        var _isDirty = false;
        $(document).ready(function () {            

            // Set exclude CSS class on radio-button list elements
            $('table.srSearch input:radio').addClass("srSearch");

            $("input[type='text'],input[type='radio'],select,textarea").not(".srSearch").change(function () {
                _isDirty = true;
            });
        });

        $(window).bind('beforeunload', function () {
            if (_isDirty) {
                return 'You have unsaved changes.';
            }
        });        


      var unsaved = false;
    $(":input").change(function () {         
        unsaved = true;
    });

    function unloadPage() {         
        if (unsaved) {             
          alert("You have unsaved changes on this page. Do you want to leave this page and discard your changes or stay on this page?");
        }
    } 

window.onbeforeunload = unloadPage;


This is exactly what the Fleegix.js plugin fleegix.form.diff (http://js.fleegix.org/plugins/form/diff) was created for. Serialize the initial state of the form on load using fleegix.form.toObject (http://js.fleegix.org/ref#fleegix.form.toObject) and save it in a variable, then compare with the current state using fleegix.form.diff on unload. Easy as pie.


One method, using arrays to hold the variables so changes can be tracked.

Here's a very simple method to detect changes, but the rest isn't as elegant.

Another method which is fairly simple and small, from Farfetched Blog:

<body onLoad="lookForChanges()" onBeforeUnload="return warnOfUnsavedChanges()">
<form>
<select name=a multiple>
 <option value=1>1
 <option value=2>2
 <option value=3>3
</select>
<input name=b value=123>
<input type=submit>
</form>

<script>
var changed = 0;
function recordChange() {
 changed = 1;
}
function recordChangeIfChangeKey(myevent) {
 if (myevent.which && !myevent.ctrlKey && !myevent.ctrlKey)
  recordChange(myevent);
}
function ignoreChange() {
 changed = 0;
}
function lookForChanges() {
 var origfunc;
 for (i = 0; i < document.forms.length; i++) {
  for (j = 0; j < document.forms[i].elements.length; j++) {
   var formField=document.forms[i].elements[j];
   var formFieldType=formField.type.toLowerCase();
   if (formFieldType == 'checkbox' || formFieldType == 'radio') {
    addHandler(formField, 'click', recordChange);
   } else if (formFieldType == 'text' || formFieldType == 'textarea') {
    if (formField.attachEvent) {
     addHandler(formField, 'keypress', recordChange);
    } else {
     addHandler(formField, 'keypress', recordChangeIfChangeKey);
    }
   } else if (formFieldType == 'select-multiple' || formFieldType == 'select-one') {
    addHandler(formField, 'change', recordChange);
   }
  }
  addHandler(document.forms[i], 'submit', ignoreChange);
 }
}
function warnOfUnsavedChanges() {
 if (changed) {
  if ("event" in window) //ie
   event.returnValue = 'You have unsaved changes on this page, which will be discarded if you leave now. Click "Cancel" in order to save them first.';
  else //netscape
   return false;
 }
}
function addHandler(target, eventName, handler) {
 if (target.attachEvent) {
  target.attachEvent('on'+eventName, handler);
 } else {
  target.addEventListener(eventName, handler, false);
 }
}
</script>

In IE document.ready will not work properly it will update the values of input.

so we need to bind load event inside the document.ready function that will handle for IE browser also.

below is the code you should put inside the document.ready function.

 $(document).ready(function () {
   $(window).bind("load", function () { 
    $("input, select").change(function () {});
   });
});

참고URL : https://stackoverflow.com/questions/155739/detecting-unsaved-changes

반응형