ASP.NET, jQuery, грязные формы и window.onbeforeunload - PullRequest
12 голосов
/ 05 августа 2009

В моем веб-приложении ASP.NET я пытаюсь создать универсальный способ предупреждения пользователей перед тем, как перейти от формы, когда они внесли изменения, с помощью jQuery. Довольно стандартные вещи, но после долгих поисков мне еще предстоит найти технику, которая работает.

Вот что у меня есть на данный момент:

    addToPostBack = function(func) {
        var old__doPostBack = __doPostBack;
        if (typeof __doPostBack != 'function') {
            __doPostBack = func;
        } else {
            __doPostBack = function() {
                old__doPostBack();
                func();
            }
        }
    }

    var isDirty = false;

    $(document).ready(function() {
        addToPostBack(function() {
            alert("Postback detected.")
            clearDirty();
        });
        $(':input').bind("change select keydown", setDirty);
        window.onbeforeunload = function(e) {
            var msg = "You have unsaved changes. "
            if (isDirty == true) {
                var e = e || window.event;
                if (e) { e.returnValue = msg; }
                return msg;
            }
        };
    });

    setDirty = function() {isDirty = true;}

    clearDirty = function() {isDirty = false;}

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

  1. На странице есть кнопки Сохранить, Отмена и Удалить
  2. На странице могут быть другие кнопки ссылок, которые выполняют функции на стороне сервера, оставаясь на той же странице
  3. Могут быть и другие элементы управления с autopostback = true, к которым также прикреплены серверные функции, но которые не приводят к тому, что пользователь покидает страницу.

Ничто из этого не должно вызывать предупреждение, поскольку пользователь не покидает страницу. Мой код пытается перехватить addToPostBack ( подробнее об этом в этом вопросе ), чтобы очистить бит isDirty перед отправкой назад, но проблема в том, что в IE onbeforeunload срабатывает до __doPostBack, по-видимому, потому что IE запускает onbeforeunload немедленно при нажатии на ссылку (, как описано здесь ).

Конечно, я мог бы подключить каждый из этих элементов управления, чтобы очистить бит isDirty, но я бы предпочел решение, которое работает на уровне формы и не требует, чтобы я касался каждого элемента управления, который мог бы вызвать обратную передачу ,

Есть ли у кого-нибудь подход, который работает в ASP.NET и не предусматривает подключения всех элементов управления, которые могут вызвать обратную передачу?

Ответы [ 5 ]

8 голосов
/ 17 февраля 2011

Я наткнулся на этот пост, пока Гуглял, чтобы найти решение для того же самого в MVC. Это решение, адаптированное из вышеприведенного описания Херба, похоже, хорошо работает. Поскольку в этом нет ничего специфичного для MVC, он должен работать точно так же для PHP, Classic ASP или любых других приложений, использующих HTML и JQuery.

var isDirty = false;

$(document).ready(function () {
    $(':input').bind("change select keydown", setDirty);
    $('form').submit(clearDirty);

    window.onbeforeunload = function (e) {
        var msg = "You have unsaved changes. "
        if (isDirty == true) {
            var e = e || window.event;
            if (e) { e.returnValue = msg; }
            return msg;
        }
    };
});

setDirty = function () { isDirty = true; }
clearDirty = function () { isDirty = false; }
2 голосов
/ 06 февраля 2010

Интересно, но ... почему вы не делаете все с помощью jQuery?

var  defaultSubmitControl = false;
var  dirty = false;
$(document).ready(function( ) {
    $('form').submit(function( ) { dirty = false });
    $(window).unload(function( ) {
        if ( dirty && confirm('Save?') ) {
            __doPastBack(defaultSubmitControl || $('form :submit[id]').get(0).id, '');
        }
    });
});
···
dirty = true;
···

Теперь, если это все еще вызывает ту же проблему (unload срабатывает до submit), вы можете попробовать другое дерево событий , поэтому вместо непосредственного вызова __doPostBack вы делаете ...

setTimeout(function( ) {
    __doPastBack(defaultSubmitControl || $('form :submit[id]').get(0).id, '');
}, 1);  // I think using 0 (zero) works too

Я не пробовал это, и это из головы, но я думаю, что это может быть способ решить это.

2 голосов
/ 05 августа 2009

Вы всегда можете создать унаследованный класс страниц, который имеет собственный метод OnLoad / OnUnload, который добавляет в JavaScript немедленное выполнение.

Тогда вам не нужно обрабатывать его на определенном уровне управления, а скорее на уровне формы / страницы.

1 голос
/ 27 августа 2010

Получил это, по сути, отслеживая положение мыши. Имейте в виду, что вы все равно можете получить положительные значения для вашего значения Y (отсюда и мой <50 строк кода), но пока ваши кнопки отправки более чем на 100 пикселей, с вами все будет в порядке. </p>

Вот Javascript, который я добавил для отслеживания изменений мыши и захвата события onbeforeunload:

    <script language="JavaScript1.2">
    <!--

    // Detect if the browser is IE or not.
    // If it is not IE, we assume that the browser is NS.
    var IE = document.all?true:false

    // If NS -- that is, !IE -- then set up for mouse capture
    if (!IE) document.captureEvents(Event.MOUSEMOVE)

    // Set-up to use getMouseXY function onMouseMove
    document.onmousemove = getMouseXY;

    // Temporary variables to hold mouse x-y pos.s
    var tempX = 0
    var tempY = 0

    // Main function to retrieve mouse x-y pos.s

    function getMouseXY(e) {
      if (IE) { // grab the x-y pos.s if browser is IE
        tempX = event.clientX + document.body.scrollLeft
        tempY = event.clientY + document.body.scrollTop
      } else {  // grab the x-y pos.s if browser is NS
        tempX = e.pageX
        tempY = e.pageY
      }  
      // catch possible negative values in NS4
      if (tempX < 0){tempX = 0}
      if (tempY < 0){tempY = 0}  
      // show the position values in the form named Show
      // in the text fields named MouseX and MouseY
      document.Show.MouseX.value = tempX
      document.Show.MouseY.value = tempY
      return true
    }

    //-->
    </script>


    <script type="text/javascript">

        window.onbeforeunload = HandleOnClose;

        function HandleOnClose(e) {

            var posY = 0;
            var elem = document.getElementsByName('MouseY');
            if (elem[0]) {
                posY = elem[0].value;
            }

            if (posY < 50) {    // Your form "submit" buttons will hopefully be more than 100 pixels down due to movement
                return "You have not selected an option, are you sure you want to close?";
            }
        }

    </script>

Затем просто добавьте следующую форму на свою страницу:

    <form name="Show">
        <input type="hidden" name="MouseX" value="0" size="4">
        <input type="hidden" name="MouseY" value="0" style="display:block" size="0">
    </form>

И это все! Он может использовать небольшую очистку (удалить MouseX и т. Д.), Но это сработало в моем существующем приложении ASP.net 3.5 и я подумал, что я опубликую, чтобы помочь кому-нибудь. Работает в IE 7 и Firefox 3.6, еще не пробовал Chrome.

0 голосов
/ 18 мая 2010

Я тоже за этим ухаживаю, но я обнаружил, что решение, которое использует все html-элементы вместо веб-элементов управления asp.net, вы думаете об этом?

  <script type="text/javascript">
    $(document).ready(function () {
      $("form").dirty_form();
      $("#btnCancel").dirty_stopper();
    });             
  </script>
...