У моїй заявці є кілька сторінок із формами.
Як я можу захистити форму таким чином, що якщо хтось переходить або закриває вкладку браузера, їм буде запропоновано підтвердити, що вони дійсно хочуть залишити форму із збереженими даними?
У моїй заявці є кілька сторінок із формами.
Як я можу захистити форму таким чином, що якщо хтось переходить або закриває вкладку браузера, їм буде запропоновано підтвердити, що вони дійсно хочуть залишити форму із збереженими даними?
Відповіді:
Це можна зробити, обробляючи beforeunload
подію та повертаючи ненульовий рядок :
window.addEventListener("beforeunload", function (e) {
var confirmationMessage = 'It looks like you have been editing something. '
+ 'If you leave before saving, your changes will be lost.';
(e || window.event).returnValue = confirmationMessage; //Gecko + IE
return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc.
});
Проблема такого підходу полягає в тому, що подача форми також знімає подію вивантаження . Це легко виправити, додавши прапор, який ви надсилаєте у форму:
var formSubmitting = false;
var setFormSubmitting = function() { formSubmitting = true; };
window.onload = function() {
window.addEventListener("beforeunload", function (e) {
if (formSubmitting) {
return undefined;
}
var confirmationMessage = 'It looks like you have been editing something. '
+ 'If you leave before saving, your changes will be lost.';
(e || window.event).returnValue = confirmationMessage; //Gecko + IE
return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc.
});
};
Потім зателефонувавши сетеві при надсиланні:
<form method="post" onsubmit="setFormSubmitting()">
<input type="submit" />
</form>
Але читайте далі ...
Ви також не хочете показувати це повідомлення, коли користувач нічого не змінив у ваших формах . Одне рішення - використовувати beforeunload
подію в поєднанні з "брудним" прапором, який запускає лише підказку, якщо це дійсно актуально.
var isDirty = function() { return false; }
window.onload = function() {
window.addEventListener("beforeunload", function (e) {
if (formSubmitting || !isDirty()) {
return undefined;
}
var confirmationMessage = 'It looks like you have been editing something. '
+ 'If you leave before saving, your changes will be lost.';
(e || window.event).returnValue = confirmationMessage; //Gecko + IE
return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc.
});
};
Зараз для реалізації isDirty
методу існують різні підходи.
Можна використовувати jQuery і формувати серіалізацію , але такий підхід має деякі недоліки. Спочатку вам потрібно змінити код для роботи в будь-якій формі ( $("form").each()
буде зроблено), але найбільша проблема полягає в тому, що jQuery serialize()
працюватиме лише на названих, невідключених елементах, тому зміна будь-якого відключеного чи безіменного елемента не спричинить брудний прапор. Для цього існують способи вирішення , як-от зробити керування заново лише замість увімкнення, серіалізації та повторного відключення елементів керування.
Тож події здаються дорогою. Ви можете спробувати прослуховувати натискання клавіш . Ця подія має кілька питань:
change
Подія також не викликає на значеннях , встановлених в коді JavaScript , так і не буде працювати для віртуальних входів.
Прив’язка input
події до всіх input
s (і textarea
s і select
s) на вашій сторінці не працюватиме у старих браузерах, і, як і всі рішення щодо обробки подій, згадані вище, не підтримує скасування. Коли користувач змінює текстове поле, а потім скасовує це або перевіряє та знімає прапорець, форма все ще вважається брудною.
І коли ви захочете реалізувати більше поведінки, як-от ігнорування певних елементів, вам доведеться ще більше працювати.
Тож перш ніж задуматися про втілення цих рішень та всіх необхідних способів вирішення, усвідомте, що ви винаходите колесо, і ви схильні до виникнення проблем, які інші вирішили за вас.
Якщо у вашій програмі вже використовується jQuery, ви можете використовувати перевірений, підтримуваний код замість того, щоб прокручувати свій власний, і використовувати для цього все бібліотеку третьої частини. jQuery Ви впевнені? плагін чудово працює, дивіться їх демо-сторінку . Це так просто, як це:
<script src="jquery.are-you-sure.js"></script>
<script>
$(function() {
$('#myForm').areYouSure(
{
message: 'It looks like you have been editing something. '
+ 'If you leave before saving, your changes will be lost.'
}
);
});
</script>
Зверніть увагу, що Firefox 4 не підтримував власні повідомлення в цьому діалоговому вікні. З квітня 2016 року впроваджується Chrome 51, в якому також видаляються користувацькі повідомлення .
Деякі варіанти існують в інших місцях на цьому веб-сайті, але я думаю, що такий діалог досить зрозумілий:
Ви хочете залишити цей сайт?
Внесені вами зміни не можуть бути збережені.
Leave Stay
Перевірте події JavaScript перед завантаженням . Це нестандартний JavaScript, представлений корпорацією Майкрософт, однак він працює в більшості браузерів, і їх документація перед завантаженням містить більше інформації та прикладів.
через jquery
$('#form').data('serialize',$('#form').serialize()); // On load save form current state
$(window).bind('beforeunload', function(e){
if($('#form').serialize()!=$('#form').data('serialize'))return true;
else e=null; // i.e; if form state change show warning box, else don't show it.
});
Ви можете скористатись функцією Google JQuery Form Serialize, вона збере всі входи форми та збереже їх у масиві. Я думаю, цього пояснення достатньо :)
Універсальне рішення, що не потребує конфігурації, яка автоматично визначає всі вхідні зміни, включаючи змістовні елементи:
"use strict";
(() => {
const modified_inputs = new Set;
const defaultValue = "defaultValue";
// store default values
addEventListener("beforeinput", (evt) => {
const target = evt.target;
if (!(defaultValue in target || defaultValue in target.dataset)) {
target.dataset[defaultValue] = ("" + (target.value || target.textContent)).trim();
}
});
// detect input modifications
addEventListener("input", (evt) => {
const target = evt.target;
let original;
if (defaultValue in target) {
original = target[defaultValue];
} else {
original = target.dataset[defaultValue];
}
if (original !== ("" + (target.value || target.textContent)).trim()) {
if (!modified_inputs.has(target)) {
modified_inputs.add(target);
}
} else if (modified_inputs.has(target)) {
modified_inputs.delete(target);
}
});
// clear modified inputs upon form submission
addEventListener("submit", () => {
modified_inputs.clear();
// to prevent the warning from happening, it is advisable
// that you clear your form controls back to their default
// state after submission
});
// warn before closing if any inputs are modified
addEventListener("beforeunload", (evt) => {
if (modified_inputs.size) {
const unsaved_changes_warning = "Changes you made may not be saved.";
evt.returnValue = unsaved_changes_warning;
return unsaved_changes_warning;
}
});
})();
Побудований поверх чудової ідеї Васіма А. використовувати серіалізацію. Проблема полягала в тому, що попередження було також показане під час подання форми. Це було виправлено тут.
var isSubmitting = false
$(document).ready(function () {
$('form').submit(function(){
isSubmitting = true
})
$('form').data('initial-state', $('form').serialize());
$(window).on('beforeunload', function() {
if (!isSubmitting && $('form').serialize() != $('form').data('initial-state')){
return 'You have unsaved changes which will not be saved.'
}
});
})
Він перевірений у Chrome та IE 11.
Виходячи з попередніх відповідей та зв'язаних разом з різних місць переповнення стека, ось таке рішення, яке я придумав, вирішує ситуацію, коли ви хочете надіслати свої зміни:
window.thisPage = window.thisPage || {};
window.thisPage.isDirty = false;
window.thisPage.closeEditorWarning = function (event) {
if (window.thisPage.isDirty)
return 'It looks like you have been editing something' +
' - if you leave before saving, then your changes will be lost.'
else
return undefined;
};
$("form").on('keyup', 'textarea', // You can use input[type=text] here as well.
function () {
window.thisPage.isDirty = true;
});
$("form").submit(function () {
QC.thisPage.isDirty = false;
});
window.onbeforeunload = window.thisPage.closeEditorWarning;
Варто відзначити, що, здається, IE11 вимагає, щоб closeEditorWarning
функція поверталася, undefined
щоб вона не показувала сповіщення.
QC.thisPage.isDirty = false;
бути window.thisPage.isDirty = false;
? Таким чином, він перевірить, чи подаєте ви форму, і не з’явиться попередження. Здавалося, працює на мої тести. Також більшість форм мають input
скоріше, ніж а textarea
. Я використав наступне, що працює досить добре:$("form").on('keyup', 'textarea,input,select', function () {
Наступний однокласник працював на мене.
window.onbeforeunload = s => modified ? "" : null;
Просто встановіть modified
значення true або false в залежності від стану вашої програми.
undefined
а не так, null
як IE буде друкувати "null", якщо modified
false.
Наступний код чудово працює. Вам потрібно досягти змін вхідних елементів ваших форм за допомогою атрибута id:
var somethingChanged=false;
$('#managerForm input').change(function() {
somethingChanged = true;
});
$(window).bind('beforeunload', function(e){
if(somethingChanged)
return "You made some changes and it's not saved?";
else
e=null; // i.e; if form state change show warning box, else don't show it.
});
});
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;
Ви можете використовувати serialize (), щоб створити текстовий рядок, закодований URL, серіалізуючи значення форми та перевірити, чи змінилась форма перед завантаженням
$(document).ready(function(){
var form = $('#some-form'),
original = form.serialize()
form.submit(function(){
window.onbeforeunload = null
})
window.onbeforeunload = function(){
if (form.serialize() != original)
return 'Are you sure you want to leave?'
}
})
Перейдіть за цим посиланням https://coderwall.com/p/gny70a/alert-when-leaving-page-with-unsaved-form Автор Володимир Сидоренко
serialize()
, і вони мають свої недоліки.
Додавши до ідеї @codecaster, ви можете додати це на кожну сторінку з формою (у моєму випадку я використовую її у глобальному вигляді, тому лише у формах було б це попередження) змінити його функцію на
if ( formSubmitting || document.getElementsByTagName('form').length == 0)
Також надішліть форми подання, включаючи вхід та кнопки скасування, посилання, тому коли людина натискає скасувати або надсилає форму, не спровокує попередження також на кожній сторінці з формою ...
<a class="btn btn-danger btn-md" href="back/url" onclick="setFormSubmitting()">Cancel</a>
Ви можете ознайомитись з детальним поясненням тут: http://techinvestiasures.redexp.in/comppare-of-form-values-on-load-and-before-close/ порівняння- for -value-values-on-load-and -поперед
Основний код:
function formCompare(defaultValues, valuesOnClose) {
// Create arrays of property names
var aPropsFormLoad = Object.keys(defaultValues);
var aPropsFormClose = Object.keys(valuesOnClose);
// If number of properties is different,
// objects are not equivalent
if (aPropsFormLoad.length != aPropsFormClose.length) {
return false;
}
for (var i = 0; i < aPropsFormLoad.length; i++) {
var propName = aPropsFormLoad[i];
// If values of same property are not equal,
// objects are not equivalent
if (defaultValues[aPropsFormLoad]+"" !== valuesOnClose[aPropsFormLoad]+"") {
return false;
}
}
// If we made it this far, objects
// are considered equivalent
return true;
}
//add polyfill for older browsers, as explained on the link above
//use the block below on load
for(i=0; i < document.forms[0].elements.length; i++){
console.log("The field name is: " + document.forms[0].elements[i].name +
" and it’s value is: " + document.forms[0].elements[i].value );
aPropsFormLoad[i] = document.forms[0].elements[i].value;
}
//create a similar array on window unload event.
//and call the utility function
if (!formCompare(aPropsOnLoad, aPropsOnClose))
{
//perform action:
//ask user for confirmation or
//display message about changes made
}
Коротка відповідь:
let pageModified = true
window.addEventListener("beforeunload",
() => pageModified ? 'Close page without saving data?' : null
)
Рішення Eerik Sven Puudist ...
var isSubmitting = false;
$(document).ready(function () {
$('form').submit(function(){
isSubmitting = true
})
$('form').data('initial-state', $('form').serialize());
$(window).on('beforeunload', function() {
if (!isSubmitting && $('form').serialize() != $('form').data('initial-state')){
return 'You have unsaved changes which will not be saved.'
}
});
})
... спонтанно зробив роботу для мене в складній об'єктно-орієнтованій обстановці без необхідних змін.
Єдина зміна, яку я застосував, - це стосуватися конкретної форми (лише одна форма на файл) під назвою "formForm" ("форма" -> "#formForm"):
<form ... id="formForm" name="formForm" ...>
Особливо добре зроблено той факт, що кнопка подання "залишається в спокої".
Крім того, він працює для мене і з останньою версією Firefox (станом на 7 лютого 2019 року).
Універсальне рішення тестованого Елі Грей працювало лише після того, як я спростив код до
'use strict';
(() => {
const modified_inputs = new Set();
const defaultValue = 'defaultValue';
// store default values
addEventListener('beforeinput', evt => {
const target = evt.target;
if (!(defaultValue in target.dataset)) {
target.dataset[defaultValue] = ('' + (target.value || target.textContent)).trim();
}
});
// detect input modifications
addEventListener('input', evt => {
const target = evt.target;
let original = target.dataset[defaultValue];
let current = ('' + (target.value || target.textContent)).trim();
if (original !== current) {
if (!modified_inputs.has(target)) {
modified_inputs.add(target);
}
} else if (modified_inputs.has(target)) {
modified_inputs.delete(target);
}
});
addEventListener(
'saved',
function(e) {
modified_inputs.clear()
},
false
);
addEventListener('beforeunload', evt => {
if (modified_inputs.size) {
const unsaved_changes_warning = 'Changes you made may not be saved.';
evt.returnValue = unsaved_changes_warning;
return unsaved_changes_warning;
}
});
})();
Зміни до нього видаляються з використанням target[defaultValue]
та лише використаннямtarget.dataset[defaultValue]
для зберігання реального значення за замовчуванням.
І я додав слухача "збереженого" події, де "збережена" подія буде запущена власноруч після того, як ваша операція збереження вдалася.
Але це "універсальне" рішення працює лише в браузерах, а не у веб-перегляді програми, наприклад, у веб-переглядачах.
Щоб змусити його працювати у веб-браузерах (частково), ще одне вдосконалення:
'use strict';
(() => {
const modified_inputs = new Set();
const defaultValue = 'defaultValue';
// store default values
addEventListener('beforeinput', evt => {
const target = evt.target;
if (!(defaultValue in target.dataset)) {
target.dataset[defaultValue] = ('' + (target.value || target.textContent)).trim();
}
});
// detect input modifications
addEventListener('input', evt => {
const target = evt.target;
let original = target.dataset[defaultValue];
let current = ('' + (target.value || target.textContent)).trim();
if (original !== current) {
if (!modified_inputs.has(target)) {
modified_inputs.add(target);
}
} else if (modified_inputs.has(target)) {
modified_inputs.delete(target);
}
if(modified_inputs.size){
const event = new Event('needSave')
window.dispatchEvent(event);
}
});
addEventListener(
'saved',
function(e) {
modified_inputs.clear()
},
false
);
addEventListener('beforeunload', evt => {
if (modified_inputs.size) {
const unsaved_changes_warning = 'Changes you made may not be saved.';
evt.returnValue = unsaved_changes_warning;
return unsaved_changes_warning;
}
});
const ua = navigator.userAgent.toLowerCase();
if(/MicroMessenger/i.test(ua)) {
let pushed = false
addEventListener('needSave', evt => {
if(!pushed) {
pushHistory();
window.addEventListener("popstate", function(e) {
if(modified_inputs.size) {
var cfi = confirm('确定要离开当前页面嘛?' + JSON.stringify(e));
if (cfi) {
modified_inputs.clear()
history.go(-1)
}else{
e.preventDefault();
e.stopPropagation();
}
}
}, false);
}
pushed = true
});
}
function pushHistory() {
var state = {
title: document.title,
url: "#flag"
};
window.history.pushState(state, document.title, "#flag");
}
})();
Я зробив це по-іншому, поділившись тут, щоб хтось міг отримати допомогу, перевірену лише в Chrome.
Я хотів попередити користувача перед закриттям вкладки, лише якщо є якісь зміни.
<input type="text" name="field" value="" class="onchange" />
var ischanged = false;
$('.onchange').change(function () {
ischanged = true;
});
window.onbeforeunload = function (e) {
if (ischanged) {
return "Make sure to save all changes.";
}
};
Це добре, але я отримав інший випуск, коли я надсилаю форму, я отримую небажане попередження, я побачив багато вирішення цього питання, це тому, що перед завантаженням пожеж перед тим, як подати, тому ми не можемо впоратися з нею під час подання події, як onbeforeunload = null
, але onclick подія запуску кнопки подання перед цими обома подіями, тому я оновив код
var isChanged = false;
var isSubmit = false;
window.onbeforeunload = function (e) {
if (isChanged && (!isSubmit)) {
return "Make sure to save all changes.";
}
};
$('#submitbutton').click(function () {
isSubmit = true;
});
$('.onchange').change(function () {
isChanged = true;
});
Перш за все, більшість браузерів за замовчуванням має цю функцію. І навіщо вам це взагалі потрібно? Чому б не зберегти форму синхронізованою? Я маю на увазі, збережіть його на будь-яких змінах, не чекаючи від користувачів жодного повідомлення. Як це роблять Google Контакти. Звичайно, якщо тільки всі поля у формі є обов'язковими. Користувачі не люблять, коли їх змушують щось заповнити, не маючи можливості піти, щоб подумати, чи потрібно це. :)
save it on any change without waiting any submitting from user
Ви не завжди хочете це робити. Іноді користувач хоче внести багато змін, а потім переглянути і підтвердити, що вони хочуть зберегти його.