Başvurumda formları olan bazı sayfalar var.
Formu, birisi tarayıcı sekmesinden ayrılırsa veya kapatırsa, formu gerçekten kaydedilmemiş verilerle terk etmek istediklerini onaylamaları istenecek şekilde nasıl güvenceye alabilirim?
Başvurumda formları olan bazı sayfalar var.
Formu, birisi tarayıcı sekmesinden ayrılırsa veya kapatırsa, formu gerçekten kaydedilmemiş verilerle terk etmek istediklerini onaylamaları istenecek şekilde nasıl güvenceye alabilirim?
Yanıtlar:
Bunu , beforeunload
olayı işleyip boş olmayan bir dize döndürerek yapabilirsiniz :
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.
});
Bu yaklaşımdaki sorun, form göndermenin de boşaltma olayını tetiklemesidir . Bu, bir form gönderdiğiniz bayrak ekleyerek kolayca giderilir:
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.
});
};
Sonra gönderirken ayarlayıcıyı arayın:
<form method="post" onsubmit="setFormSubmitting()">
<input type="submit" />
</form>
Ama okuyun ...
Kullanıcı, formlarınızda hiçbir şey değiştirmediğinde de bu mesajı göstermek istemezsiniz . Çözümlerden biri, beforeunload
olayı yalnızca gerçekten ilgili olduğunda istemi tetikleyen "kirli" bir bayrakla birlikte kullanmaktır .
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.
});
};
Şimdi isDirty
yöntemi uygulamak için çeşitli yaklaşımlar var.
JQuery ve form serileştirmeyi kullanabilirsiniz , ancak bu yaklaşımın bazı kusurları vardır. Öncelikle kodu herhangi bir form üzerinde çalışacak şekilde değiştirmeniz gerekir ( $("form").each()
yapacak), ancak en büyük sorun jQuery'nin serialize()
yalnızca adlandırılmış, devre dışı olmayan öğeler üzerinde çalışacağıdır, bu nedenle herhangi bir devre dışı veya adlandırılmamış öğeyi değiştirmek kirli bayrağı tetiklemez. Bunun için geçici çözümler var kontrolleri etkinleştirmek, serileştirmek ve sonra tekrar devre dışı bırakmak yerine kontrolleri salt okunur yapmak gibi .
Yani olaylar gidilecek yol gibi görünüyor. Tuşlara basmayı dinlemeyi deneyebilirsiniz . Bu etkinliğin birkaç sorunu var:
change
Olay da JavaScript kodundan belirlenen değerlere tetiklemez yüzden de, sanal girişler için olmaz işi.
Bağlama input
tüm olay input
s (ve textarea
s ve select
s) sayfanızda olmaz eski tarayıcılarda çalışması tüm olay işleme çözümleri gibi ve, geri alma desteklemez, yukarıda bahsedilen. Kullanıcı bir metin kutusunu değiştirip geri alırsa veya bir onay kutusunu işaretleyip işaretini kaldırırsa, form hala kirli kabul edilir.
Ve belirli unsurları göz ardı etmek gibi daha fazla davranış uygulamak istediğinizde, daha da fazla işiniz olacak.
Dolayısıyla, bu çözümleri ve gerekli tüm geçici çözümleri uygulamayı düşünmeden önce, tekerleği yeniden icat ettiğinizi ve başkalarının sizin için zaten çözdüğü sorunlarla karşılaşmaya eğilimli olduğunuzu anlayın.
Uygulamanız zaten jQuery kullanıyorsa, kendi yuvarlamak yerine test edilmiş, bakımı yapılmış bir kod kullanabilir ve bunların tümü için bir üçüncü bölüm kitaplığı kullanabilirsiniz. jQuery Emin misiniz? eklenti harika çalışıyor, demo sayfalarına bakın . Bu kadar basit:
<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'ün bu iletişim kutusunda özel mesajları desteklemediğini unutmayın . Nisan 2016 itibarıyla, özel mesajların da kaldırıldığı Chrome 51 kullanıma sunuldu .
Bu sitenin başka yerlerinde bazı alternatifler var, ancak bunun gibi bir iletişim kutusunun yeterince açık olduğunu düşünüyorum:
Bu siteden ayrılmak istiyor musunuz?
Yaptığınız değişiklikler kaydedilemeyebilir.
Leave Stay
Yüklemeden önce JavaScript etkinliğine göz atın . Microsoft tarafından sunulan standart dışı bir JavaScripttir, ancak çoğu tarayıcıda çalışır ve önceden yüklenmemiş belgelerinde daha fazla bilgi ve örnek bulunur.
jquery ile
$('#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 Serileştirme işlevini kullanabilirsiniz, bu tüm form girdilerini toplar ve diziye kaydeder. Sanırım bu açıklama yeterli :)
İçeriği düzeltilebilir öğeler de dahil olmak üzere tüm giriş değişikliklerini otomatik olarak algılayan hiçbir yapılandırma gerektirmeyen evrensel çözüm:
"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;
}
});
})();
Wasim A.'nin serileştirmeyi kullanma konusundaki mükemmel fikrinin üzerine inşa edilmiştir . Sorun, form gönderilirken de uyarının gösterilmesiydi. Bu burada düzeltildi.
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 ve IE 11'de test edilmiştir.
Önceki yanıtlara dayanarak ve yığın taşması içindeki çeşitli yerlerden birlikte taşlanmış, işte, değişikliklerinizi gerçekten göndermek istediğinizde davayı ele alan çözüm buldum:
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'in bir uyarı göstermemesi için closeEditorWarning
işlevin geri dönmesini gerektirdiğini belirtmek gerekir undefined
.
QC.thisPage.isDirty = false;
olmak window.thisPage.isDirty = false;
? Bu şekilde, formu gönderip göndermediğinizi kontrol eder ve bir uyarı göstermez. Testlerim için işe yarıyor gibiydi. Ayrıca, çoğu formda input
a yerine bir textarea
. Oldukça iyi çalışan aşağıdakileri kullandım:$("form").on('keyup', 'textarea,input,select', function () {
Aşağıdaki tek astar benim için çalıştı.
window.onbeforeunload = s => modified ? "" : null;
Sadece set modified
için gerçek veya sahte uygulamanın durumuna bağlı olarak.
undefined
ziyade geri dönün . null
modified
Aşağıdaki kod harika çalışıyor. Form öğelerinizin giriş değişikliklerine id niteliği üzerinden erişmeniz gerekir:
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;
Form değerlerini serileştirerek URL kodlu metin dizesi oluşturmak ve serialize (formun yüklenmeden önce değişip değişmediğini kontrol etmek için serialize () kullanabilirsiniz.
$(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?'
}
})
Bu bağlantıya bakın https://coderwall.com/p/gny70a/alert-when-leaving-page-with-unsaved-form Yazan Vladimir Sidorenko
serialize()
ve aslında dezavantajları var.
@ Codecaster fikrini ekleyerek bir formla her sayfaya ekleyebilirsin (benim durumumda küresel şekilde kullanıyorum, böylece sadece formlarda bu uyarıda bulunacaktı) işlevini değiştirmek için
if ( formSubmitting || document.getElementsByTagName('form').length == 0)
Ayrıca, giriş ve iptal düğmeleri bağlantılarını içeren formları gönderin, böylece kişi iptal et veya formu gönderdiğinde, form olmadan her sayfada uyarıyı tetiklemez ...
<a class="btn btn-danger btn-md" href="back/url" onclick="setFormSubmitting()">Cancel</a>
Ayrıntılı bir açıklama için buraya bakabilirsiniz : http://techinvestigations.redexp.in/comparison-of-form-values-on-load-and-before-close/ formdaki değerlerin karşılaştırılması bakılırsa-yakın
Ana kod:
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
}
Kısa cevap:
let pageModified = true
window.addEventListener("beforeunload",
() => pageModified ? 'Close page without saving data?' : null
)
Eerik Sven Puudist'in çözümü ...
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.'
}
});
})
... işi kendiliğinden karmaşık bir nesne yönelimli ortamda herhangi bir değişiklik yapmadan yaptı.
Uyguladığım tek değişiklik, "formForm" ('form' -> '#formForm') adı verilen somut forma (dosya başına yalnızca bir form) başvurmaktı:
<form ... id="formForm" name="formForm" ...>
Özellikle iyi yapılması, gönder düğmesinin "yalnız bırakılması" gerçeğidir.
Ayrıca, benim için de en son Firefox sürümü ile çalışıyor (7 Şubat 2019 itibariyle).
Eli Grey'in evrensel çözümü test edildi, ancak kodu basitleştirdikten sonra çalıştı
'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;
}
});
})();
Onun üzerinde yapılan değişiklikler target[defaultValue]
sadece kullanımı ve kullanımı silinir.target.dataset[defaultValue]
gerçek varsayılan değerin saklanması için .
Ve kaydetme işleminiz başarılı olduğunda 'kaydedilen' etkinliğin kendiniz tarafından tetikleneceği bir 'kaydedilmiş' olay dinleyicisi ekledim.
Ancak bu 'evrensel' çözüm yalnızca tarayıcılarda çalışır, uygulamanın web görünümünde, örneğin wechat tarayıcılarında çalışmaz.
Wechat tarayıcılarında (kısmen) çalışmasını sağlamak için, yine başka bir gelişme:
'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");
}
})();
Farklı bir şekilde yaptım, burada paylaşarak birinin yardım alabilmesi için yalnızca Chrome ile test edildi.
Yalnızca bazı değişiklikler olduğunda sekmeyi kapatmadan önce kullanıcıyı uyarmak istedim.
<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.";
}
};
İyi çalışıyor, ama başka bir sorun var, ben istenmeyen uyarı olsun formu gönderdiğinizde, ben üzerinde geçici çözüm bir sürü gördüm, bunun nedeni onubforeload önce yangınlar neden bu gibi onubmit olay ele olamaz onbeforeunload = null
, Gönder düğmesi onclick olayı her iki olaydan önce patlar, bu yüzden kodu güncelledi
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;
});
Her şeyden önce, çoğu tarayıcı varsayılan olarak bu işleve sahiptir. Ve neden buna hiç ihtiyacınız var? Formu neden senkronize halde tutmuyorsunuz? Yani, kullanıcıdan herhangi bir göndermeyi beklemeden herhangi bir değişikliğe kaydedin. Google Kişiler gibi. Tabii ki sadece formdaki tüm alanlar zorunluysa. Kullanıcılar, bir şeye ihtiyaç duyup duymadıklarını düşünmeye başlamadan bir şeyi doldurmaya zorlandıklarından hoşlanmazlar. :)
save it on any change without waiting any submitting from user
Bunu her zaman yapmak istemezsiniz. Bazen kullanıcı birçok değişiklik yapmak ve ardından kaydetmek istediğini gözden geçirip onaylamak ister.