Обнаружение несохраненных изменений - PullRequest
87 голосов
/ 01 октября 2008

У меня есть требование для реализации приглашения «Несохраненные изменения» в приложении ASP .Net. Если пользователь изменяет элементы управления в веб-форме и пытается уйти перед сохранением, должен появиться запрос, предупреждающий их об несохраненных изменениях, и предоставляющий им возможность отменить и остаться на текущей странице. Подсказка не должна отображаться, если пользователь не коснулся ни одного из элементов управления.

В идеале я хотел бы реализовать это в JavaScript, но прежде чем идти по пути развертывания собственного кода, существуют ли какие-либо платформы или рекомендуемые шаблоны проектирования для достижения этой цели? В идеале я хотел бы, чтобы что-то можно было легко использовать на нескольких страницах с минимальными изменениями.

Ответы [ 15 ]

89 голосов
/ 01 октября 2008

Использование jQuery:

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

При необходимости используйте onunload / onbeforeunload методы.

Из комментариев, следующие ссылки на все поля ввода, без дублирования кода:

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

Использование $(":input") относится ко всем элементам input, textarea, select и button.

41 голосов
/ 01 октября 2008

Один кусочек пазла:

/**
 * 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.

17 голосов
/ 01 октября 2008

На странице .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..
9 голосов
/ 16 ноября 2009

Следующее использует функцию onbeforeunload браузера и jquery для захвата любого события onchange. ИТ-отдел также ищет любые кнопки отправки или сброса для сброса флага, указывающего на произошедшие изменения.

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;
7 голосов
/ 02 октября 2008

Спасибо всем за ответы. В итоге я реализовал решение с использованием JQuery и плагина Protect-Data . Это позволяет мне автоматически применять мониторинг ко всем элементам управления на странице.

Однако есть несколько предостережений, особенно при работе с приложением ASP .Net:

  • Когда пользователь выбирает опцию отмены, функция doPostBack выдаст ошибку JavaScript. Мне пришлось вручную сделать попытку получения вызова .submit внутри doPostBack, чтобы подавить его.

  • На некоторых страницах пользователь может выполнить действие, которое выполняет обратную передачу на ту же страницу, но не сохраняет. Это приводит к сбросу любой логики JavaScript, поэтому он думает, что ничего не изменилось после обратной передачи, когда что-то может иметь место. Мне пришлось реализовать скрытое текстовое поле, которое отправляется обратно со страницей и используется для хранения простого логического значения, указывающего, являются ли данные грязными. Это сохраняется для постбэков.

  • Возможно, вы захотите, чтобы некоторые постбэки на странице не вызывали диалог, например кнопка «Сохранить». В этом случае вы можете использовать JQuery для добавления функции OnClick, которая устанавливает для window.onbeforeunload значение null.

Надеюсь, это полезно для всех, кто должен реализовать нечто подобное.

6 голосов
/ 21 мая 2015

Общее решение Поддержка нескольких форм на данной странице ( Просто скопируйте и вставьте в свой проект )

$(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.
6 голосов
/ 22 октября 2013

Вот простое решение javascript / jquery. Он учитывает "отмены" пользователем, он инкапсулирован в функцию для простоты применения и не пропускает при отправке. Просто вызовите функцию и передайте идентификатор вашей формы.

Эта функция сериализует форму один раз при загрузке страницы и еще раз до того, как пользователь покидает страницу. Если два состояния формы различаются, отображается приглашение.

Попробуйте: 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');
});
6 голосов
/ 25 мая 2009

Следующее решение работает для прототипа (протестировано в FF, IE 6 и Safari). Он использует общий наблюдатель формы (который запускает форму: изменен, когда были изменены любые поля формы), который вы можете использовать и для других вещей.

/* 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);
4 голосов
/ 15 декабря 2014

Определить изменения формы с помощью jQuery очень просто:

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

// check for form changes
if ($('#formId').serialize() != formInitVal) {
    // show confirmation alert
}
4 голосов
/ 30 апреля 2012

Недавно я внес вклад в плагин jQuery с открытым исходным кодом, который называется dirtyForms .

Плагин предназначен для работы с динамически добавляемым HTML, поддерживает несколько форм, может поддерживать практически любые диалоговые рамки, использует диалоговое окно браузера перед загрузкой, имеет подключаемую вспомогательную среду для поддержки получения грязного статуса из пользовательских редакторов (плагин tinyMCE включен), работает в iFrames, и состояние «грязный» можно установить или сбросить по желанию.

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

...