window.onbeforeunload - показывать предупреждение только при отсутствии формы

Я использую window.onbeforeunload, чтобы пользователь не перемещался после изменения значений в форме. Это работает нормально, за исключением того, что оно также показывает предупреждение, когда пользователь отправляет форму (не желателен).

Как я могу это сделать, не показывая предупреждение при отправке формы?

Текущий код:

var formHasChanged = false;

$(document).on('change', 'form.confirm-navigation-form input, form.confirm-navigation-form select, form.confirm-navigation-form textarea', function (e) {
    formHasChanged = true;
});

$(document).ready(function () {
    window.onbeforeunload = function (e) {
        if (formHasChanged) {
            var message = "You have not saved your changes.", e = e || window.event;
            if (e) {
                e.returnValue = message;
            }
            return message;
        }
    }
});

Ответ 1

Использование формы submit для установки флага может сработать для вас.

 var formHasChanged = false;
 var submitted = false;

$(document).on('change', 'form.confirm-navigation-form input, form.confirm-navigation-form select, form.confirm-navigation-form textarea', function (e) {
    formHasChanged = true;
});

$(document).ready(function () {
    window.onbeforeunload = function (e) {
        if (formHasChanged && !submitted) {
            var message = "You have not saved your changes.", e = e || window.event;
            if (e) {
                e.returnValue = message;
            }
            return message;
        }
    }
 $("form").submit(function() {
     submitted = true;
     });
});

Ответ 2

вы можете использовать.on() для привязки onbeforeunload и затем использовать.off(), чтобы отвязать его при отправке формы

$(document).ready(function () {
    // Warning
    $(window).on('beforeunload', function(){
        return "Any changes will be lost";
    });

    // Form Submit
    $(document).on("submit", "form", function(event){
        // disable warning
        $(window).off('beforeunload');
    });
}

Ответ 3

Вы можете обработать событие submit(), которое будет происходить только для отправки вашей формы.

В этом случае установите для переменной флага formHasChanged значение false, чтобы разрешить выгрузку. Кроме того, просто предложение, но поскольку назначение переменной этого флага изменилось, вы можете захотеть переименовать его как "warnBeforeUnload",

$(document).submit(function(){
    warnBeforeUnload = false;
});

Ответ 4

Я искал лучшее решение этого. Мы хотим просто исключить один или несколько триггеров из создания нашего "Вы уверены"? диалоговое окно. Поэтому мы не должны создавать все больше и больше обходных решений для все большего количества побочных эффектов. Что делать, если форма отправляется без click кнопки отправки? Что делать, если наш обработчик isDirty удаляет статус isDirty но затем форма-submit блокируется впоследствии? Конечно, мы можем изменить поведение наших триггеров, но правильным местом будет логика обработки диалога. Привязка к форме submit событие вместо привязки к кнопки отправки click событие является преимуществом ответов в этой теме выше некоторых других я видел раньше, но это ИМХО просто исправляет неправильный подход.

После некоторого копания в событии события onbeforeunload я обнаружил свойство .target.activeElement, которое содержит элемент, который инициировал событие изначально. Итак, yay, это кнопка или ссылка или все, что мы нажали (или вообще ничего, если сам браузер не прошел). Наш "Ты уверен?" диалоговая логика затем сводится к следующим двум компонентам:

  1. isDirty обработка формы:

    $('form.pleaseSave').on('change', function() {
      $(this).addClass('isDirty');
    });
    
  2. "Ты уверен?" диалоговая логика:

    $(window).on('beforeunload', function(event) {
      // if form is dirty and trigger doesn't have a ignorePleaseSave class
      if ($('form.pleaseSave').hasClass('isDirty')
          && !$(event.target.activeElement).hasClass('ignorePleaseSave')) {
        return "Are you sure?"
      }
      // special hint: returning nothing doesn't summon a dialog box
    });
    

Это просто так. Обходных решений не требуется. Просто дайте триггеры (submit и другие кнопки действий) класс ignorePleaseSave и форму, которую мы хотим получить, чтобы диалог был применен к классу pleaseSave. Все остальные причины для разгрузки страницы вызывают наш "Ты уверен?" Диалог.

PS Я использую jQuery здесь, но я думаю, что свойство .target.activeElement также доступно в обычном JavaScript.