У меня есть требование реализовать запрос «Несохраненные изменения» в приложении 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")
относится ко всем элементам input, textarea, select и button.источник
change
для ввода текста срабатывает один раз при выходе / потере фокуса, тогда какinput
триггеры для каждого нажатия клавиши. (Обычно я использую его вместеchange
с JQueryone()
, чтобы предотвратить множественные события.)Одна часть головоломки:
/** * 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
регистрацию событий.источник
onclick="window.onbeforeunload=null"
)На странице .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. ИТ-специалисты также ищут любые кнопки отправки или сброса, чтобы сбросить флаг, указывающий, что изменения произошли.
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. Мне пришлось вручную поставить try-catch вокруг вызова .submit в doPostBack, чтобы подавить его.
На некоторых страницах пользователь может выполнить действие, которое выполняет обратную передачу на ту же страницу, но не сохраняет. Это приводит к сбросу любой логики JavaScript, поэтому он думает, что ничего не изменилось после обратной передачи, когда что-то могло измениться. Мне пришлось реализовать скрытое текстовое поле, которое отправляется обратно со страницей и используется для хранения простого логического значения, указывающего, являются ли данные грязными. Это сохраняется во всех обратных передачах.
Вы можете захотеть, чтобы некоторые обратные передачи на странице не вызывали диалоговое окно, например, кнопка «Сохранить». В этом случае вы можете использовать JQuery для добавления функции OnClick, которая устанавливает для window.onbeforeunload значение null.
Надеюсь, это будет полезно для всех, кому нужно реализовать что-то подобное.
источник
Общее решение Поддержка нескольких форм на данной странице ( просто скопируйте и вставьте в свой проект )
$(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; }); });
Примечание. Это решение объединено с решениями других компаний для создания общего интегрированного решения.
Особенности:
источник
_isDirty
переменной, как описано Аароном Пауэллом. Я не видел необходимости добавлять и удалять классы из HTML вместо переменных в javascript.Следующее решение работает для прототипа (протестировано в 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);
источник
Вот простое решение 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'); });
источник
Недавно я внес свой вклад в плагин jQuery с открытым исходным кодом под названием dirtyForms .
Плагин разработан для работы с динамически добавляемым HTML, поддерживает несколько форм, может поддерживать практически любую диалоговую структуру, возвращается к браузеру перед диалоговым окном выгрузки, имеет подключаемую вспомогательную структуру для поддержки получения грязного статуса из пользовательских редакторов (плагин tinyMCE включен) , работает в iFrames, а грязный статус можно установить или сбросить по желанию.
https://github.com/snikch/jquery.dirtyforms
источник
Обнаружить изменения формы с помощью jQuery очень просто:
var formInitVal = $('#formId').serialize(); // detect form init value after form is displayed // check for form changes if ($('#formId').serialize() != formInitVal) { // show confirmation alert }
источник
Я расширил предложение Слэйса, приведенное выше, включив в него большинство редактируемых элементов, а также исключив определенные элементы (здесь используется стиль CSS, называемый «srSearch») из установки флага грязных данных.
<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;
источник
Именно это и есть плагин Fleegix.js
fleegix.form.diff
(http://js.fleegix.org/plugins/form/diff ) был создан для. Сериализуйте начальное состояние формы при загрузке, используяfleegix.form.toObject
(http://js.fleegix.org/ref#fleegix.form.toObject ) и сохраните его в переменной, затем сравните с текущим состоянием, используяfleegix.form.diff
при выгрузке. Проще простого.источник
Один метод , использующий массивы для хранения переменных, чтобы можно было отслеживать изменения.
Вот очень простой метод обнаружения изменений , но остальное не так элегантно.
Еще один довольно простой и небольшой метод из блога 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>
источник
В IE document.ready не будет работать должным образом, он обновит значения ввода.
поэтому нам нужно привязать событие загрузки внутри функции document.ready, которая также будет обрабатываться для браузера IE.
ниже приведен код, который следует поместить в функцию document.ready.
$(document).ready(function () { $(window).bind("load", function () { $("input, select").change(function () {}); }); });
источник