it-swarm.com.de

Erkennen nicht gespeicherter Änderungen

Ich muss eine Eingabeaufforderung "Nicht gespeicherte Änderungen" in einer ASP .Net-Anwendung implementieren. Wenn ein Benutzer Steuerelemente in einem Webformular ändert und versucht, vor dem Speichern zu navigieren, sollte eine Eingabeaufforderung angezeigt werden Warnen Sie sie, dass sie nicht gespeicherte Änderungen vorgenommen haben, und geben Sie ihnen die Option, abzubrechen und auf der aktuellen Seite zu bleiben. Die Eingabeaufforderung sollte nicht angezeigt werden, wenn der Benutzer keines der Steuerelemente berührt hat.

Idealerweise würde ich dies gerne in JavaScript implementieren, aber bevor ich mich auf den Weg mache, meinen eigenen Code zu rollen, gibt es irgendwelche vorhandenen Frameworks oder empfohlenen Entwurfsmuster, um dies zu erreichen? Idealerweise hätte ich gerne etwas, das mit minimalen Änderungen problemlos über mehrere Seiten hinweg wiederverwendet werden kann.

88
tbreffni

Verwenden von jQuery:

var _isDirty = false;
$("input[type='text']").change(function(){
  _isDirty = true;
});
// replicate for other input types and selects

Kombinieren Sie nach Bedarf mit den Methoden onunload/onbeforeunload.

In den Kommentaren wird auf alle Eingabefelder verwiesen, ohne den Code zu duplizieren:

$(':input').change(function () {

Die Verwendung von $(":input") bezieht sich auf alle Eingabe-, Textbereichs-, Auswahl- und Schaltflächenelemente.

91
Aaron Powell

Ein Teil des Puzzles:

/**
 * Determines if a form is dirty by comparing the current value of each element
 * with its default value.
 *
 * @param {Form} form the form to be checked.
 * @return {Boolean} <code>true</code> if the form is dirty, <code>false</code>
 *                   otherwise.
 */
function formIsDirty(form) {
  for (var i = 0; i < form.elements.length; i++) {
    var element = form.elements[i];
    var type = element.type;
    if (type == "checkbox" || type == "radio") {
      if (element.checked != element.defaultChecked) {
        return true;
      }
    }
    else if (type == "hidden" || type == "password" ||
             type == "text" || type == "textarea") {
      if (element.value != element.defaultValue) {
        return true;
      }
    }
    else if (type == "select-one" || type == "select-multiple") {
      for (var j = 0; j < element.options.length; j++) {
        if (element.options[j].selected !=
            element.options[j].defaultSelected) {
          return true;
        }
      }
    }
  }
  return false;
}

nd noch ein :

window.onbeforeunload = function(e) {
  e = e || window.event;  
  if (formIsDirty(document.forms["someForm"])) {
    // For IE and Firefox
    if (e) {
      e.returnValue = "You have unsaved changes.";
    }
    // For Safari
    return "You have unsaved changes.";
  }
};

Wickeln Sie alles ein, und was bekommen Sie?

var confirmExitIfModified = (function() {
  function formIsDirty(form) {
    // ...as above
  }

  return function(form, message) {
    window.onbeforeunload = function(e) {
      e = e || window.event;
      if (formIsDirty(document.forms[form])) {
        // For IE and Firefox
        if (e) {
          e.returnValue = message;
        }
        // For Safari
        return message;
      }
    };
  };
})();

confirmExitIfModified("someForm", "You have unsaved changes.");

Möglicherweise möchten Sie auch die Registrierung des Ereignishandlers beforeunload ändern, um die Ereignisregistrierung von LIBRARY_OF_CHOICE Zu verwenden.

41
Jonny Buchanan

Auf der ASPX-Seite benötigen Sie eine JavaScript-Funktion, um festzustellen, ob die Formularinformationen "unsauber" sind.

<script language="javascript">
    var isDirty = false;

    function setDirty() {
        isDirty = true;
    }

    function checkSave() {
        var sSave;
        if (isDirty == true) {
            sSave = window.confirm("You have some changes that have not been saved. Click OK to save now or CANCEL to continue without saving.");
            if (sSave == true) {
                document.getElementById('__EVENTTARGET').value = 'btnSubmit';
                document.getElementById('__EVENTARGUMENT').value = 'Click';  
                window.document.formName.submit();
            } else {
                 return true;
            }
        }
    }
</script>
<body class="StandardBody" onunload="checkSave()">

fügen Sie im Codebehind die Trigger in die Eingabefelder ein und setzen Sie die Submit/Cancel-Schaltflächen zurück.

btnSubmit.Attributes.Add("onclick", "isDirty = 0;");
btnCancel.Attributes.Add("onclick", "isDirty = 0;");
txtName.Attributes.Add("onchange", "setDirty();");
txtAddress.Attributes.Add("onchange", "setDirty();");
//etc..
17
Wayne

Im Folgenden werden die Onbeforunload-Funktion und die JQuery des Browsers zum Erfassen von Onchange-Ereignissen verwendet. IT sucht auch nach Senden- oder Zurücksetzen-Schaltflächen, um das Flag zurückzusetzen, das Änderungen anzeigt.

dataChanged = 0;     // global variable flags unsaved changes      

function bindForChange(){    
     $('input,checkbox,textarea,radio,select').bind('change',function(event) { dataChanged = 1})
     $(':reset,:submit').bind('click',function(event) { dataChanged = 0 })
}


function askConfirm(){  
    if (dataChanged){ 
        return "You have some unsaved changes.  Press OK to continue without saving." 
    }
}

window.onbeforeunload = askConfirm;
window.onload = bindForChange;
9
Colin Houghton

Danke für die Antworten an alle. Am Ende implementierte ich eine Lösung mit JQuery und dem Protect-Data Plug-In. Dadurch kann ich die Überwachung automatisch auf alle Steuerelemente auf einer Seite anwenden.

Es gibt jedoch einige Vorbehalte, insbesondere beim Umgang mit einer ASP .Net-Anwendung:

  • Wenn ein Benutzer die Abbruchoption auswählt, wird durch die doPostBack-Funktion ein JavaScript-Fehler ausgelöst. Ich musste den .submit-Aufruf in doPostBack manuell mit einem Try-Catch umgehen, um ihn zu unterdrücken.

  • Auf einigen Seiten kann ein Benutzer eine Aktion ausführen, bei der ein Postback auf derselben Seite ausgeführt wird, dies ist jedoch keine Speicherung. Dies führt zu einem Zurücksetzen der JavaScript-Logik, sodass davon ausgegangen wird, dass sich nach dem Postback nichts geändert hat, wenn sich etwas geändert hat. Ich musste ein verstecktes Textfeld implementieren, das mit der Seite zurückgesendet wird und einen einfachen booleschen Wert enthält, der angibt, ob die Daten verschmutzt sind. Dies wird über Postbacks hinweg beibehalten.

  • Möglicherweise möchten Sie, dass einige Postbacks auf der Seite das Dialogfeld nicht auslösen, z. B. die Schaltfläche Speichern. In diesem Fall können Sie mit JQuery eine OnClick-Funktion hinzufügen, die window.onbeforeunload auf null setzt.

Hoffentlich ist dies hilfreich für alle anderen, die etwas Ähnliches implementieren müssen.

7
tbreffni

Die folgende Lösung funktioniert für Prototypen (getestet in FF, IE 6 und Safari). Sie verwendet einen generischen Formularbeobachter (der das Formular auslöst: geändert, wenn Felder des Formulars geändert wurden) Sie können auch für andere Sachen verwenden.

/* use this function to announce changes from your own scripts/event handlers.
 * Example: onClick="makeDirty($(this).up('form'));"
 */
function makeDirty(form) {
    form.fire("form:changed");
}

function handleChange(form, event) {
    makeDirty(form);
}

/* generic form observer, ensure that form:changed is being fired whenever
 * a field is being changed in that particular for
 */
function setupFormChangeObserver(form) {
    var handler = handleChange.curry(form);

    form.getElements().each(function (element) {
        element.observe("change", handler);
    });
}

/* installs a form protector to a form marked with class 'protectForm' */
function setupProtectForm() {
    var form = $$("form.protectForm").first();

    /* abort if no form */
    if (!form) return;

    setupFormChangeObserver(form);

    var dirty = false;
    form.observe("form:changed", function(event) {
        dirty = true;
    });

    /* submitting the form makes the form clean again */
    form.observe("submit", function(event) {
        dirty = false;
    });

    /* unfortunatly a propper event handler doesn't appear to work with IE and Safari */
    window.onbeforeunload = function(event) {
        if (dirty) {
            return "There are unsaved changes, they will be lost if you leave now.";
        }
    };
}

document.observe("dom:loaded", setupProtectForm);
6
reto

Allgemeine Lösung Unterstützung mehrerer Formulare auf einer bestimmten Seite (Kopieren Sie sie einfach und fügen Sie sie in Ihr Projekt ein)

$(document).ready(function() {
    $('form :input').change(function() {
        $(this).closest('form').addClass('form-dirty');
    });

    $(window).bind('beforeunload', function() {
        if($('form:not(.ignore-changes).form-dirty').length > 0) {
            return 'You have unsaved changes, are you sure you want to discard them?';
        }
    });

    $('form').bind('submit',function() {
        $(this).closest('form').removeClass('form-dirty');
        return true;
    });
});

Hinweis: Diese Lösung wird aus den Lösungen anderer kombiniert, um eine allgemeine integrierte Lösung zu erstellen.

Eigenschaften:

  • Einfach kopieren und in deine App einfügen.
  • Unterstützt mehrere Formulare.
  • Sie können Formulare formatieren oder verschmutzen, da sie die Klasse "formularverschmutzt" haben.
  • Sie können einige Formulare ausschließen, indem Sie die Klasse "Änderungen ignorieren" hinzufügen.
6
MhdSyrwan

Hier ist eine einfache JavaScript/JQuery-Lösung. Es ist für das "Rückgängigmachen" durch den Benutzer verantwortlich, ist zur Vereinfachung der Anwendung in eine Funktion gekapselt und löst beim Senden keine Fehlzündungen aus. Rufen Sie einfach die Funktion auf und übergeben Sie die ID Ihres Formulars.

Diese Funktion serialisiert das Formular einmal beim Laden der Seite und erneut, bevor der Benutzer die Seite verlässt. Wenn sich die beiden Formularstatus unterscheiden, wird die Eingabeaufforderung angezeigt.

Probieren Sie es aus: http://jsfiddle.net/skibulk/Ydt7Y/

function formUnloadPrompt(formSelector) {
    var formA = $(formSelector).serialize(), formB, formSubmit = false;

    // Detect Form Submit
    $(formSelector).submit( function(){
        formSubmit = true;
    });

    // Handle Form Unload    
    window.onbeforeunload = function(){
        if (formSubmit) return;
        formB = $(formSelector).serialize();
        if (formA != formB) return "Your changes have not been saved.";
    };
}

$(function(){
    formUnloadPrompt('form');
});
6
skibulk

Das Erkennen von Formularänderungen mithilfe von jQuery ist ganz einfach:

var formInitVal = $('#formId').serialize(); // detect form init value after form is displayed

// check for form changes
if ($('#formId').serialize() != formInitVal) {
    // show confirmation alert
}
4
v.babak

Ich habe kürzlich zu einem Open-Source-jQuery-Plugin namens dirtyForms beigetragen.

Das Plugin wurde für die Arbeit mit dynamisch hinzugefügtem HTML entwickelt, unterstützt mehrere Formulare, kann praktisch jedes Dialog-Framework unterstützen, greift auf den Browser vor dem Laden des Dialogs zurück und verfügt über ein Plug-in-Hilfs-Framework, um den Status von benutzerdefinierten Editoren zu erhalten (ein tinyMCE-Plugin ist enthalten). funktioniert innerhalb von iFrames und der Dirty-Status kann nach Belieben gesetzt oder zurückgesetzt werden.

https://github.com/snikch/jquery.dirtyforms

4
NightOwl888

Ich habe den obigen Vorschlag von Slace erweitert, um die meisten bearbeitbaren Elemente einzuschließen und auch bestimmte Elemente (mit einem CSS-Stil namens "srSearch" hier) davon auszuschließen, dass das Dirty-Flag gesetzt wird.

<script type="text/javascript">
        var _isDirty = false;
        $(document).ready(function () {            

            // Set exclude CSS class on radio-button list elements
            $('table.srSearch input:radio').addClass("srSearch");

            $("input[type='text'],input[type='radio'],select,textarea").not(".srSearch").change(function () {
                _isDirty = true;
            });
        });

        $(window).bind('beforeunload', function () {
            if (_isDirty) {
                return 'You have unsaved changes.';
            }
        });        
2
PeterX
      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;

2
Ankit

Genau dafür wurde das Fleegix.js-Plugin fleegix.form.diff ( http://js.fleegix.org/plugins/form/diff ) erstellt. Serialisieren Sie den Anfangszustand des Formulars beim Laden mit fleegix.form.toObject ( http://js.fleegix.org/ref#fleegix.form.toObject ) und Speichern Sie es in einer Variablen und vergleichen Sie es beim Entladen mit fleegix.form.diff mit dem aktuellen Status. Einfach wie Torte.

1
mde

In IE document.ready wird nicht richtig funktionieren, es wird die Werte der Eingabe aktualisieren.

daher müssen wir das Ladeereignis in die document.ready - Funktion einbinden, die auch für den IE - Browser gilt.

im Folgenden finden Sie den Code, den Sie in die document.ready-Funktion einfügen sollten.

 $(document).ready(function () {
   $(window).bind("load", function () { 
    $("input, select").change(function () {});
   });
});
0
Krupall

Eine Methode Verwenden von Arrays zum Speichern der Variablen, damit Änderungen nachverfolgt werden können.

Hier ist eine sehr einfache Methode, um Änderungen zu erkennen , aber der Rest ist nicht so elegant.

Eine andere Methode, die ziemlich einfach und klein ist, von Farfetched Blog :

<body onLoad="lookForChanges()" onBeforeUnload="return warnOfUnsavedChanges()">
<form>
<select name=a multiple>
 <option value=1>1
 <option value=2>2
 <option value=3>3
</select>
<input name=b value=123>
<input type=submit>
</form>

<script>
var changed = 0;
function recordChange() {
 changed = 1;
}
function recordChangeIfChangeKey(myevent) {
 if (myevent.which && !myevent.ctrlKey && !myevent.ctrlKey)
  recordChange(myevent);
}
function ignoreChange() {
 changed = 0;
}
function lookForChanges() {
 var origfunc;
 for (i = 0; i < document.forms.length; i++) {
  for (j = 0; j < document.forms[i].elements.length; j++) {
   var formField=document.forms[i].elements[j];
   var formFieldType=formField.type.toLowerCase();
   if (formFieldType == 'checkbox' || formFieldType == 'radio') {
    addHandler(formField, 'click', recordChange);
   } else if (formFieldType == 'text' || formFieldType == 'textarea') {
    if (formField.attachEvent) {
     addHandler(formField, 'keypress', recordChange);
    } else {
     addHandler(formField, 'keypress', recordChangeIfChangeKey);
    }
   } else if (formFieldType == 'select-multiple' || formFieldType == 'select-one') {
    addHandler(formField, 'change', recordChange);
   }
  }
  addHandler(document.forms[i], 'submit', ignoreChange);
 }
}
function warnOfUnsavedChanges() {
 if (changed) {
  if ("event" in window) //ie
   event.returnValue = 'You have unsaved changes on this page, which will be discarded if you leave now. Click "Cancel" in order to save them first.';
  else //netscape
   return false;
 }
}
function addHandler(target, eventName, handler) {
 if (target.attachEvent) {
  target.attachEvent('on'+eventName, handler);
 } else {
  target.addEventListener(eventName, handler, false);
 }
}
</script>
0
Adam Davis