У моїй заявці є кілька сторінок із формами.
Як я можу захистити форму таким чином, що якщо хтось переходить або закриває вкладку браузера, їм буде запропоновано підтвердити, що вони дійсно хочуть залишити форму із збереженими даними?
У моїй заявці є кілька сторінок із формами.
Як я можу захистити форму таким чином, що якщо хтось переходить або закриває вкладку браузера, їм буде запропоновано підтвердити, що вони дійсно хочуть залишити форму із збереженими даними?
Відповіді:
Це можна зробити, обробляючи 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події до всіх inputs (і textareas і selects) на вашій сторінці не працюватиме у старих браузерах, і, як і всі рішення щодо обробки подій, згадані вище, не підтримує скасування. Коли користувач змінює текстове поле, а потім скасовує це або перевіряє та знімає прапорець, форма все ще вважається брудною.
І коли ви захочете реалізувати більше поведінки, як-от ігнорування певних елементів, вам доведеться ще більше працювати.
Тож перш ніж задуматися про втілення цих рішень та всіх необхідних способів вирішення, усвідомте, що ви винаходите колесо, і ви схильні до виникнення проблем, які інші вирішили за вас.
Якщо у вашій програмі вже використовується 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", якщо modifiedfalse.
Наступний код чудово працює. Вам потрібно досягти змін вхідних елементів ваших форм за допомогою атрибута 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Ви не завжди хочете це робити. Іноді користувач хоче внести багато змін, а потім переглянути і підтвердити, що вони хочуть зберегти його.