Вопрос

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

В идеале я хотел бы реализовать это на 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") относится ко всем элементам ввода, textarea, select и button.

Другие советы

Один кусочек головоломки:

/**
 * 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.Он также ищет любые кнопки отправки или сброса, чтобы сбросить флажок, указывающий на произошедшие изменения.

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 и Защита данных подключаемый модуль.Это позволяет мне автоматически применять мониторинг ко всем элементам управления на странице.

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

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

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

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

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

Следующее решение работает для prototype (протестировано в 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.Он учитывает "отмены" пользователем, он инкапсулирован в функцию для удобства применения и не дает осечки при отправке.Просто вызовите функцию и передайте идентификатор вашей формы.

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

Попробуйте это сделать: 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'.

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

Плагин предназначен для работы с динамически добавляемым 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 = выгрузить страницу;

Это именно то, что нужно для 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 на разгрузке.Проще простого.

Один из методов, используя массивы для хранения переменных, чтобы можно было отслеживать изменения.

Вот очень простой способ обнаружение изменений, но в остальном все не так элегантно.

Другой метод, который является довольно простым и небольшим, из Надуманный Блог:

<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 () {});
   });
});
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top