Ostrzeż użytkownika przed opuszczeniem strony internetowej z niezapisanymi zmianami


341

Mam kilka stron z formularzami w mojej aplikacji.

Jak mogę zabezpieczyć formularz w taki sposób, że jeśli ktoś opuści lub zamknie kartę przeglądarki, powinien zostać poproszony o potwierdzenie, że naprawdę chce opuścić formularz z niezapisanymi danymi?



3
To pytanie powinno zawierać odpowiedź, której szukasz: stackoverflow.com/questions/1244535/...
Nexerus


Odpowiedzi:


556

Krótka, zła odpowiedź:

Możesz to zrobić, obsługując beforeunloadzdarzenie i zwracając ciąg inny niż zero :

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.
});

Problem z tym podejściem polega na tym, że przesłanie formularza powoduje także zwolnienie zdarzenia . Można to łatwo naprawić, dodając flagę, którą przesyłasz formularz:

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.
    });
};

Następnie dzwoniąc do setera podczas przesyłania:

<form method="post" onsubmit="setFormSubmitting()">     
    <input type="submit" />
</form>

Ale czytaj dalej ...

Długa, poprawna odpowiedź:

Nie chcesz również wyświetlać tej wiadomości, gdy użytkownik nic nie zmienił w formularzach . Jednym z rozwiązań jest użycie beforeunloadzdarzenia w połączeniu z flagą „brudną”, która uruchamia monit tylko wtedy, gdy jest naprawdę istotny.

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.
    });
};

Aby wdrożyć tę isDirtymetodę, istnieją różne podejścia.

Możesz używać jQuery i serializacji formularzy , ale to podejście ma pewne wady. Najpierw musisz zmienić kod, aby działał w dowolnej formie ( $("form").each()zrobi to), ale największym problemem jest to, że jQuery serialize()będzie działał tylko na nazwanych, nie wyłączonych elementach, więc zmiana dowolnego wyłączonego lub nienazwanego elementu nie wyzwoli brudnej flagi. Istnieją obejścia tego problemu , takie jak dokonywanie kontroli tylko do odczytu zamiast włączania, serializacji, a następnie ponownego wyłączania kontroli.

Wydaje się, że wydarzenia powinny się odbyć. Możesz spróbować odsłuchać naciśnięcia klawiszy . To wydarzenie ma kilka problemów:

  • Nie uruchamia się w polach wyboru, przyciskach radiowych ani innych elementach zmienianych za pomocą myszy.
  • Uruchomi się w przypadku nieistotnych naciśnięć klawiszy, takich jak Ctrlklawisz.
  • Nie wyzwala wartości ustawionych za pomocą kodu JavaScript.
  • Nie uruchamia się przy wycinaniu lub wklejaniu tekstu w menu kontekstowych.
  • Nie będzie działać w przypadku wirtualnych danych wejściowych, takich jak datepickers lub upiększające pola wyboru / przyciski radiowe, które zapisują swoją wartość w ukrytych danych wejściowych za pomocą JavaScript.

changeWydarzenie również nie wywołuje na wartościach ustalonych z kodu JavaScript , więc również nie będą działać dla wejść wirtualnych.

Wiązania inputzdarzenie do wszystkich inputs (i textareaS i selectS) na swojej stronie nie będzie działać na starszych przeglądarkach i, jak wszystkie rozwiązania obsługi zdarzeń wymienionych powyżej, nie obsługuje cofania. Gdy użytkownik zmieni pole tekstowe, a następnie je cofnie, lub zaznaczy i odznaczy pole wyboru, formularz nadal będzie uważany za brudny.

A jeśli chcesz wprowadzić więcej zachowań, takich jak ignorowanie niektórych elementów, będziesz musiał wykonać jeszcze więcej pracy.

Nie wymyślaj koła ponownie:

Zanim więc pomyślisz o wdrożeniu tych rozwiązań i wszystkich wymaganych obejść, zdaj sobie sprawę, że zmieniasz kierownicę i masz skłonność do problemów, które inni już dla ciebie rozwiązali.

Jeśli twoja aplikacja korzysta już z jQuery, możesz równie dobrze użyć sprawdzonego, utrzymywanego kodu zamiast zwijania własnego, i do tego wszystkiego użyj biblioteki trzeciej części. jQuery's Are You Sure? wtyczka działa świetnie, zobacz ich stronę demo . To takie proste:

<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>

Niestandardowe wiadomości nie są obsługiwane wszędzie

Pamiętaj, że Firefox 4 nie obsługiwał niestandardowych wiadomości w tym oknie dialogowym. Od kwietnia 2016 r. Wdrażany jest Chrome 51, w którym usuwane są również niestandardowe wiadomości .

Niektóre alternatywy istnieją gdzie indziej na tej stronie, ale myślę, że takie okno dialogowe jest wystarczająco jasne:

Czy chcesz opuścić tę stronę?

Wprowadzone zmiany mogą nie zostać zapisane.

Leave Stay


6
Pamiętaj, że używanie ciągów niestandardowych nie działa już w Chrome; chromestatus.com/feature/5349061406228480
amann

5
Tak, zostało to opisane w ostatniej części mojej odpowiedzi.
CodeCaster

2
@Chris, ponieważ Angular manipuluje DOM, aby zmienić stronę, jednocześnie nie nawigując poza bieżącym dokumentem.
CodeCaster

15
Ostrzegamy, że jQuery są porzucone od 2014 roku (57 otwartych problemów na Githubie ), z mojego doświadczenia jest pełen błędów, może się wydawać, że na początku działa, ale po kilku szybkich testach zdałem sobie sprawę, że nie zawsze działa. W ogóle tego nie poleciłbym
Mark

4
@JacopoStanchi Niestety nie znalazłem. Mam na myśli, że wyglądałem całkiem sporo - ale było to już 10 stycznia, więc ktoś mógł coś napisać, ale wątpię. Najlepszym rozwiązaniem jest wdrożenie go samemu - nie jest to coś, czego tak bardzo chcesz usłyszeć. (Ale przynajmniej nie dostaniesz żadnych niespodzianek, takich jak ja za pomocą jQuery areYouSure.) Plus, kto wie, może możesz nawet zrobić to open source, a twoja implementacja zostanie udostępniona innym;)
Mark

75

Sprawdź zdarzenie onbeforeunload JavaScript . Jest to niestandardowy JavaScript wprowadzony przez Microsoft, jednak działa w większości przeglądarek, a ich dokumentacja onbeforeunload zawiera więcej informacji i przykładów.


3
Myślę, że teraz stały się standardami. >> Wydarzenie to zostało pierwotnie wprowadzone przez Microsoft w Internet Explorerze 4 i znormalizowane w specyfikacji HTML5.
vee

34

poprzez 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.
});

Możesz użyć funkcji Google Serialize formularza JQuery, która zbierze wszystkie dane wejściowe formularza i zapisze je w tablicy. Myślę, że to wyjaśnienie wystarczy :)


6
nie używać #form jako forma id ponieważ okno będzie tworzyć i forma obiektu o nazwie :)
mdikici

1
Sprawdź tutaj, jeśli to nie działa: stackoverflow.com/questions/7080269/…
Leniel Maccaferri

16

Uniwersalne rozwiązanie niewymagające konfiguracji, która automatycznie wykrywa wszystkie modyfikacje danych wejściowych, w tym elementy możliwe do zadowolenia:

"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;
    }
});
})();

1
Chłodna fasola. Wystarczy skopiować ten kod i wkleić go na stronę testową, wprowadzić zmiany i odświeżyć. Wyświetli się ostrzeżenie przeglądarki natywnej ostrzegające o niezapisanych zmianach.
TheLegendaryCopyCoder,

1
To działało dla mnie w Chrome 71.0.3578.98 (oficjalna wersja) (64-bit)
JacobRossDev

2
Działa to naprawdę dobrze, ale jeśli używasz tego z formularzem do przesłania, musisz najpierw wyczyścić zestaw zmodyfikowanych danych wejściowych, w przeciwnym razie otrzymasz alert potwierdzenia zmian. Dodałem detektor zdarzeń do mojego formularza, aby wywoływał go podczas wysyłania, i po prostu uruchomiłem funkcję set clear, w ten sposób zmodyfikowane dane wejściowe są czyste, gdy działa nasłuchiwanie zdarzenia beforeunload i pozwala na kontynuowanie wysyłania.
stepquick

1
Cool faktycznie skopiuj i wklej. dzięki za oszczędność czasu. Pracuj dla mnie w Firfox 75.0
Connectify_user

1
Uwielbiam ten fragment
Rawburner

10

Zbudowany na podstawie doskonałego pomysłu Wasim A. na zastosowanie serializacji. Problem polegał na tym, że ostrzeżenie wyświetlało się również podczas przesyłania formularza. Zostało to naprawione tutaj.

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.'
        }
    });
})

Został przetestowany w Chrome i IE 11.


Wasim A i Eerik Sven Puudist - Dzięki użyłem identyfikatora dla formularza i identyfikatora dla mojego przycisku zapisu, ponieważ wszystkie moje przyciski były typu: <formularz akcji = "" id = "marksform" metoda = "POST"> <td> <typ wejściowy = „Submit” name = "submission_button" id = "save" value = "Save"> </td> <td> <input type = "upload" name = "replace_button" value = "Next"> </td> i kilka więcej wszystkich typów przesłać Dlatego zastąpiono. Prześlij (przez konkretne kliknięcie $ („# zapisz”). click (funkcja () {isSubmitting = true}) Użyj „#marksform” zamiast „form”
Jayanta

7

Na podstawie poprzednich odpowiedzi i zebranych razem z różnych miejsc w przepełnieniu stosu, oto rozwiązanie, które wymyśliłem, które obsługuje przypadek, gdy naprawdę chcesz przesłać swoje zmiany:

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;

Warto zauważyć, że IE11 wydaje się wymagać od closeEditorWarningfunkcji powrotu, undefinedaby nie wyświetlała ostrzeżenia.


To rozwiązanie nie weryfikuje, czy jakiekolwiek wartości zostały zmienione w stosunku do ich pierwotnego stanu, w związku z czym unieważnia się je w przypadku, gdy użytkownik wprowadza tekst i usuwa wprowadzony tekst przed próbą przejścia dalej.
Brett Weber

Dobra uwaga, @BrettWeber. W takim przypadku możesz zmodyfikować closeEditorWarning i mieć „if (window.thisPage.isDirty && uiHasChanged ())”, gdzie uiHasChanged to funkcja, która wie o oryginalnym stanie z serwera i sprawdza wszystkie różnice, ale to rozwiązanie dotyczyło przypadek, w którym szczególnie nie chciałem wykonywać całej tej dodatkowej pracy, a to ma tylko fałszywie pozytywne wyniki, gdy w obszarach tekstowych dokonano rzeczywistych naciśnięć klawiszy, co uważałem za rozsądny kompromis. :)
Jonathan

Nie powinno QC.thisPage.isDirty = false;być window.thisPage.isDirty = false;? W ten sposób sprawdzi, czy przesyłasz formularz, i nie wyświetli ostrzeżenia. Wydawało się, że pracuję dla moich testów. Ponadto większość form ma inputraczej niż textarea. Użyłem następujących, które działają raczej dobrze:$("form").on('keyup', 'textarea,input,select', function () {
Mike

7

Poniższy linijka zadziałał dla mnie.

window.onbeforeunload = s => modified ? "" : null;

Wystarczy ustawić modifiedaby prawda lub fałsz w zależności od stanu aplikacji.


2
Kilka sugestii: Zwróć niestandardowy komunikat zamiast pustego ciągu, ponieważ niektóre przeglądarki go wyświetlają (np. Edge), i zwróć undefinedzamiast, nullgdy IE wypisze „null”, jeśli modifiedjest fałszem.
Kevin Lee

1
co z urządzeniami mobilnymi? Rozumiem, że urządzenia IOS nie honorują przed odciążeniem.
jaybro,

4

Poniższy kod działa świetnie. Musisz osiągnąć zmiany wejściowe elementów formularza za pomocą atrybutu 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.
            });
        });

3
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;

Wstawiłem go do osobnego pliku i dołączyłem do <script src = "warnOnChange.js"> </script>, ale nic się nie dzieje, gdy modyfikuję pole tekstowe, a następnie wykonuję polecenie nagłówka.
Fabrizio Bartolomucci,

2

Za pomocą serialize () można utworzyć ciąg tekstowy zakodowany w adresie URL, serializując wartości formularza i sprawdzając, czy formularz zmienił się przed odciążeniem

$(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?'
    }
})

Zobacz ten link https://coderwall.com/p/gny70a/alert-when-leaving-page-with-unsaved-form Wpisany przez Vladimir Sidorenko


1
Działa, ale jak odpowiedział autor kodu, istnieją pewne wady tej metody, zapoznaj się z tym wyjaśnieniem stackoverflow.com/a/7317311/10555981
Pradeep

Używa się już kilku odpowiedzi serialize()i rzeczywiście ma to swoje wady.
CodeCaster,

To powinna być poprawna odpowiedź, bardzo prosta w użyciu i działa zgodnie z oczekiwaniami.
Jodyshop

1

Dodając do idei @codecaster, możesz dodać to do każdej strony za pomocą formularza (w moim przypadku używam go w sposób globalny, więc tylko w formularzach będzie to ostrzegać) zmień jego funkcję na

if ( formSubmitting || document.getElementsByTagName('form').length == 0) 

Umieszczaj także formularze wysyłania, w tym linki logowania i przyciski anulowania, więc gdy osoba naciśnie przycisk anuluj lub prześlij formularz, nie spowoduje ostrzeżenia również na każdej stronie bez formularza ...

<a class="btn btn-danger btn-md" href="back/url" onclick="setFormSubmitting()">Cancel</a>

1

Możesz sprawdzić szczegółowe wyjaśnienie tutaj: http://techinvestigations.redexp.in/comparison-of-form-values-on-load-and-before-close/ Porównanie-wartości-form-wartości-na-obciążeniu-i -przed zamknięciem

Główny 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
    }

1

Krótka odpowiedź:

let pageModified = true

window.addEventListener("beforeunload", 
  () => pageModified ? 'Close page without saving data?' : null
)

1

Rozwiązanie Eerika Svena Puudista ...

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.'
        }
    });
})

... spontanicznie wykonał dla mnie zadanie w złożonym otoczeniu obiektowym bez żadnych zmian.

Jedyną zastosowaną przeze mnie zmianą było odwołanie się do konkretnego formularza (tylko jeden formularz na plik) o nazwie „formForm” („forma” -> „#formForm”):

<form ... id="formForm" name="formForm" ...>

Szczególnie dobrze zrobiony jest fakt, że przycisk wysyłania jest „pozostawiony sam”.

Dodatkowo działa dla mnie również z najnowszą wersją Firefoksa (z 7 lutego 2019 r.).


1

Testowałem uniwersalne rozwiązanie Eli Grey, działało dopiero po uproszczeniu kodu do

  '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;
      }
    });

  })();

Modyfikacje jego są usuwane z użycia target[defaultValue]i tylko użytkowaniatarget.dataset[defaultValue] do przechowywania rzeczywistej wartości domyślnej.

I dodałem „zapisany” detektor zdarzeń, w którym „zapisane” zdarzenie zostanie uruchomione przez ciebie po pomyślnym wykonaniu operacji zapisywania.

Ale to „uniwersalne” rozwiązanie działa tylko w przeglądarkach, a nie w widoku aplikacji, na przykład w przeglądarkach WeChat.

Aby działał również w przeglądarkach WeChat (częściowo), jeszcze raz kolejne ulepszenia:

  '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");
    }
  })();

0

Zrobiłem to inaczej, udostępniając tutaj, aby ktoś mógł uzyskać pomoc, testowany tylko z Chrome.

Chciałem ostrzec użytkownika przed zamknięciem karty tylko w przypadku pewnych zmian.

<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.";
    }        
};

Działa dobrze, ale dostałem inny problem, gdy przesyłam formularz, otrzymuję niechciane ostrzeżenie, widziałem wiele obejść tego problemu, to dlatego, że onbeforeunload uruchamia się przed przesłaniem, dlatego nie możemy sobie z tym poradzić w przypadku zdarzenia przesłania onbeforeunload = null, ale Zdarzenie onclick przycisku wysyłania odpala przed tymi dwoma zdarzeniami, więc zaktualizowałem kod

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;
});

-5

Przede wszystkim większość przeglądarek ma domyślnie tę funkcję. I dlaczego w ogóle tego potrzebujesz? Dlaczego nie chcesz zsynchronizować formularza? Mam na myśli, zapisz go przy każdej zmianie bez czekania na przesłanie przez użytkownika. Tak jak Kontakty Google. Oczywiście, jeśli tylko wszystkie pola w formularzu są obowiązkowe. Użytkownicy nie lubią, kiedy zmuszają się do wypełnienia czegoś bez możliwości odejścia i zastanowienia się, czy tego potrzebują. :)


masz rację, ale moje formularze są generowane dynamicznie, a pola nie są pod moją kontrolą, więc dla mnie nie jest możliwe prześledzenie wszystkich pól i wysłanie żądania przez ajax, jeśli masz coś na myśli, proszę podziel się ze mną.
Khan

Ok, może nie być konieczne do twoich celów, ale nadal można je wdrożyć. Jeśli elementy formularza znajdują się na ekranie, możesz dołączyć własne moduły obsługi zdarzeń i uzyskać dowolne dane. Następnie użyj AJAX, aby zapisać dane w dowolnym miejscu. Nawet jeśli formularze mają losowo generowane identyfikatory lub nazwy klas, możesz użyć XPath, jeśli możesz przewidzieć strukturę formularza. To XML / HTML, prawda? Możesz nawet mieć JAD z osobami odpowiedzialnymi za dynamicznie generowaną formę i porozmawiać o tym, w jaki sposób XSTL może pomóc wam obojgu w tym projekcie. Tylko myśl ...
SimonDever

1
save it on any change without waiting any submitting from userNie zawsze chcesz to robić. Czasami użytkownik chce wprowadzić wiele zmian, a następnie przejrzeć i potwierdzić, że chce je zapisać.
BadHorsie

1
Nie zaproponowałem przesłania formularza. Dane mogą być zapisane w localStorage, w pewnej pamięci podręcznej lub nawet przesłane z flagą roboczą. Istnieje wiele metod tego zachowania. Jest to o wiele lepsze niż powiadamianie użytkownika o tym, że nie ukończył formularza, a jeśli nie zrobi tego i zamknie okno, będzie musiał wypełnić go ponownie następnym razem. „Chodź, człowieku, nie bądź leniwy, twój pociąg / autobus / samolot itp. Nie ma znaczenia, ponieważ nie obchodzi nas, że zapomniałeś ładowarki z laptopa, po prostu wypełnij ten cholerny formularz!”
YuS
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.