it-swarm.com.de

Was ist der beste Weg, um Änderungen in einem Formular über Javascript zu verfolgen?

Ich möchte Änderungen in Eingaben in einem Formular per Javascript verfolgen. Meine Absicht ist (aber nicht begrenzt)

  • aktivieren Sie die Schaltfläche "Speichern" nur, wenn sich etwas geändert hat
  • warnung, wenn der Benutzer die Seite schließen möchte und etwas nicht gespeichert wird

Ideen?

43
Ricardo Acras

Durchlaufen Sie alle Eingabeelemente und setzen Sie jeweils einen onchange-Handler. Wenn dies ausgelöst wird, setzen Sie ein Flag, das Sie informiert, dass sich das Formular geändert hat. Eine Basisversion davon wäre sehr einfach einzurichten, wäre aber nicht intelligent genug, um zu erkennen, ob jemand eine Eingabe von "a" in "b" und dann wieder in "a" geändert hat. Wenn es wichtig wäre, diesen Fall zu erfassen, wäre dies immer noch möglich, würde aber etwas mehr Arbeit erfordern.

Hier ist ein grundlegendes Beispiel in jQuery:

$("#myForm")
    .on("input", function() {
        // do whatever you need to do when something's changed.
        // perhaps set up an onExit function on the window
        $('#saveButton').show();
    })
;
30
nickf

Textformularelemente in JS stellen eine .value-Eigenschaft und eine .defaultValue-Eigenschaft bereit, sodass Sie Folgendes implementieren können:

function formChanged(form) {
  for (var i = 0; i < form.elements.length; i++) {
      if(form.elements[i].value != form.elements[i].defaultValue) return(true);
  }
  return(false);
}

Für Kontrollkästchen und Optionsfelder sehen Sie, ob element.checked != element.defaultChecked und für HTML <select />-Elemente das select.options-Array durchlaufen werden müssen, und prüfen Sie für jede Option, ob selected == defaultSelected.

Vielleicht möchten Sie ein Framework wie jQuery verwenden, um Handler an das onchange-Ereignis jedes einzelnen Formularelements anzuhängen. Diese Handler können Ihren formChanged()-Code aufrufen und die enabled -Eigenschaft Ihrer Schaltfläche "Speichern" ändern und/oder einen Ereignishandler für das beforeunload-Ereignis des Dokumentkörpers anhängen/abtrennen.

17
Dylan Beattie

Versuchen

function isModifiedForm(form){
  var __clone = $(form).clone();
  __clone[0].reset();
  return $(form).serialize() == $(__clone).serialize();
}

Hoffe es hilft))

7
Nikita Makarov

Hier ist eine Javascript- & Jquery-Methode zum Erkennen von Formularänderungen, die einfach ist. Der Submit-Button wird deaktiviert, bis Änderungen vorgenommen werden. Es erkennt Versuche, die Seite mit anderen Mitteln als dem Senden des Formulars zu verlassen. Es berücksichtigt "Rückgängigmachen" durch den Benutzer, es ist zur Vereinfachung der Anwendung in einer Funktion gekapselt und kann beim Senden nicht fehlschlagen. 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 die beiden Formularzustände unterschiedlich sind, wird die Aufforderung angezeigt.

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

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

    // Enable & Disable Submit Button
    var formToggleSubmit = function(){
        formB = $(formSelector).serialize();
        $(formSelector+' [type="submit"]').attr( "disabled", formA == formB);
    };

    formToggleSubmit();
    $(formSelector).change(formToggleSubmit);
    $(formSelector).keyup(formToggleSubmit);
}



// Call function on DOM Ready:

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

Ich habe eine solche Frage in Ars Technica beantwortet, aber die Frage wurde so gerahmt, dass die Änderungen erkannt werden mussten, auch wenn der Benutzer kein Textfeld verwischt (in diesem Fall wird das Änderungsereignis nie ausgelöst). Ich habe ein umfassendes Skript entworfen, das:

  1. aktiviert die Schaltflächen zum Senden und Zurücksetzen, wenn sich die Feldwerte ändern
  2. deaktiviert die Schaltflächen zum Senden und Zurücksetzen, wenn das Formular zurückgesetzt wird
  3. interrupts verlassen die Seite, wenn sich die Formulardaten geändert haben und nicht gesendet wurden
  4. unterstützt IE 6+, Firefox 2+, Safari 3+ (und vermutlich Opera, aber ich habe nicht getestet)

Dieses Skript hängt von Prototype ab, kann jedoch leicht an eine andere Bibliothek oder alleine angepasst werden.

$(document).observe('dom:loaded', function(e) {
    var browser = {
        trident: !!document.all && !window.opera,
        webkit: (!(!!document.all && !window.opera) && !document.doctype) ||
            (!!window.devicePixelRatio && !!window.getMatchedCSSRules)
    };

    // Select form elements that won't bubble up delegated events (eg. onchange)
    var inputs = $('form_id').select('select, input[type="radio"], input[type="checkbox"]');

    $('form_id').observe('submit', function(e) {
        // Don't bother submitting if form not modified
        if(!$('form_id').hasClassName('modified')) {
            e.stop();
            return false;
        }
        $('form_id').addClassName('saving');
    });

    var change = function(e) {
        // Paste event fires before content has been pasted
        if(e && e.type && e.type == 'paste') {
            arguments.callee.defer();
            return false;
        }

        // Check if event actually results in changed data
        if(!e || e.type != 'change') {
            var modified = false;
            $('form_id').getElements().each(function(element) {
                if(element.tagName.match(/^textarea$/i)) {
                    if($F(element) != element.defaultValue) {
                        modified = true;
                    }
                    return;
                } else if(element.tagName.match(/^input$/i)) {
                    if(element.type.match(/^(text|hidden)$/i) && $F(element) != element.defaultValue) {
                        modified = true;
                    } else if(element.type.match(/^(checkbox|radio)$/i) && element.checked != element.defaultChecked) {
                        modified = true;
                    }
                }
            });
            if(!modified) {
                return false;
            }
        }

        // Mark form as modified
        $('form_id').addClassName('modified');

        // Enable submit/reset buttons
        $('reset_button_id').removeAttribute('disabled');
        $('submit_button_id').removeAttribute('disabled');

        // Remove event handlers as they're no longer needed
        if(browser.trident) {
            $('form_id').stopObserving('keyup', change);
            $('form_id').stopObserving('paste', change);
        } else {
            $('form_id').stopObserving('input', change);
        }
        if(browser.webkit) {
            $$('#form_id textarea').invoke('stopObserving', 'keyup', change);
            $$('#form_id textarea').invoke('stopObserving', 'paste', change);
        }
        inputs.invoke('stopObserving', 'change', arguments.callee);
    };

    $('form_id').observe('reset', function(e) {
        // Unset form modified, restart modified check...
        $('reset_button_id').writeAttribute('disabled', true);
        $('submit_button_id').writeAttribute('disabled', true);
        $('form_id').removeClassName('modified');
        startObservers();
    });

    var startObservers = (function(e) {
        if(browser.trident) {
            $('form_id').observe('keyup', change);
            $('form_id').observe('paste', change);
        } else {
            $('form_id').observe('input', change);
        }
        // Webkit apparently doesn't fire oninput in textareas
        if(browser.webkit) {
            $$('#form_id textarea').invoke('observe', 'keyup', change);
            $$('#form_id textarea').invoke('observe', 'paste', change);
        }
        inputs.invoke('observe', 'change', change);
        return arguments.callee;
    })();

    window.onbeforeunload = function(e) {
        if($('form_id').hasClassName('modified') && !$('form_id').hasClassName('saving')) {
            return 'You have unsaved content, would you really like to leave the page? All your changes will be lost.';
        }
    };

});
2
eyelidlessness

Wenn Sie ein Web-App-Framework (Rails, ASP.NET, Cake, Symfony) verwenden, sollten Pakete für die Ajax-Validierung vorhanden sein. 

http://webtecker.com/2008/03/17/list-of-ajax-form-validators/

und einige Wrapper auf onbeforeunload (), die Benutzer warnen, dass das Formular geschlossen werden soll:

http://pragmatig.wordpress.com/2008/03/03/protecting-userdata-from-beeing-lost-with-jquery/Erkennen nicht gespeicherter Änderungen

2
Gene T

Ich habe dirtyforms.js benutzt. Funktioniert gut für mich.

http://mal.co.nz/code/jquery-dirty-forms/

1
satyrFrost

Um den Benutzer vor dem Schließen zu warnen, verwenden Sie uneVor dem Laden:

window.onbeforeunload = function() {
   return "You are about to lose your form data.";
};

Ich würde jeden Feldwert in einer Variablen speichern, wenn die Seite geladen wird, und diese Werte dann vergleichen, wenn der Benutzer die Seite entlädt. Wenn Unterschiede festgestellt werden, wissen Sie, was gespeichert werden soll, und können noch besser den Benutzer darüber informieren, welche Daten beim Beenden nicht gespeichert werden.

// this example uses the prototype library
// also, it's not very efficient, I just threw it together
var valuesAtLoad = [];
var valuesOnCheck = [];
var isDirty = false;
var names = [];
Event.observe(window, 'load', function() {
    $$('.field').each(function(i) {
        valuesAtLoad.Push($F(i));
    });
});

var checkValues = function() {
    var changes = [];
    valuesOnCheck = [];
    $$('.field').each(function(i) {
        valuesOnCheck.Push($F(i));
    });

    for(var i = 0; i <= valuesOnCheck.length - 1; i++ ) {
        var source = valuesOnCheck[i];
        var compare = valuesAtLoad[i];
        if( source !== compare ) {
            changes.Push($$('.field')[i]);
        }
    }

    return changes.length > 0 ? changes : [];
};

setInterval(function() { names = checkValues().pluck('id'); isDirty = names.length > 0; }, 100);

// notify the user when they exit
Event.observe(window, 'beforeunload', function(e) {
     e.returnValue = isDirty ? "you have changed the following fields: \r\n" + names + "\r\n these changes will be lost if you exit. Are you sure you want to continue?" : true;
});
1
Jared

Ich habe einige Cross-Browser-Tests durchgeführt.

Auf Chrome und Safari ist dies Nizza:

<form onchange="validate()">
...
</form>

Für Firefox + Chrome/Safari gehe ich dazu:

<form onkeydown="validate()">
    ...
    <input type="checkbox" onchange="validate()">
</form>

Elemente wie Checkboxen oder Radiobuttons benötigen einen eigenen Ereignis-Listener.

0
Bijan

Hängen Sie einen Ereignishandler an das Onchange-Ereignis jedes Formulareingabe-/Auswahl-/Textbereiches an. Festlegen einer Variablen, um anzugeben, ob die Schaltfläche "Speichern" aktiviert werden soll. Erstellen Sie einen Onunload-Hander, der auch nach einem fehlerhaften Formular sucht. Wenn das Formular gesendet wird, setzen Sie die Variable zurück:

 window.onunload = checkUnsavedPage; 
 var isDirty = false; 
 var formElements = // Hole einen Verweis auf alle Formularelemente 
 für (var i = 0; len = formElements.length; i ++) {
 // Hinzufügen eines onchange-Ereignisses zu jedem Element, um formChanged () 
} 
.__ aufzurufen. Funktion formChanged (event) {
 isDirty = false; 
 document.getElementById ("savebtn"). disabled = ""; 
} 

 Funktion checkUnsavedPage () {
 if (isDirty) {
 var isSure = confirm ("Bist du dir sicher?"); 
 if (! isSure) {
 event.preventDefault (); 
 } 
 } 
} 
0
Eric Wendelin

Hier ist eine vollständige Umsetzung von Dylan Beatties Vorschlag :

Client/JS-Framework zum Schutz vor "nicht gesicherten Daten"?

Sie sollten keine Anfangswerte speichern müssen, um festzustellen, ob sich das Formular geändert hat, es sei denn, Sie werden auf der Clientseite dynamisch ausgefüllt (obwohl Sie selbst dann noch die default-Eigenschaften für die Formularelemente einrichten könnten).

0
Jonny Buchanan

Ich hatte die gleiche Herausforderung und dachte an eine gemeinsame Lösung. Der nachstehende Code ist nicht perfekt, er stammt von Anfang an. Im Folgenden sind die Schritte, die ich verwendet habe:

1) Verschieben Sie den folgenden JS in eine andere Datei (zB changeFramework.js).

2) Fügen Sie es in Ihr Projekt ein, indem Sie es importieren

3) Fügen Sie auf Ihrer HTML-Seite die Klasse "monitorChange" hinzu.

4) Die globale Variable 'hasChanged' zeigt an, ob sich auf der von Ihnen bearbeiteten Seite etwas geändert hat.

<script type="text/javascript" id="MonitorChangeFramework">
// MONITOR CHANGE FRAMEWORK
// ALL ELEMENTS WITH CLASS ".monitorChange" WILL BE REGISTERED FOR CHANGE
// ON CHANGE IT WILL RAISE A FLAG
var hasChanged;

function MonitorChange() {
    hasChanged = false;
    $(".monitorChange").change(function () {
        hasChanged = true;
    });
}

Im Folgenden sind die Steuerelemente aufgeführt, bei denen ich dieses Framework verwendet habe:

<textarea class="monitorChange" rows="5" cols="10" id="testArea"></textarea></br>
        <div id="divDrinks">
            <input type="checkbox" class="chb monitorChange" value="Tea" />Tea </br>
            <input type="checkbox" class="chb monitorChange" value="Milk" checked='checked' />Milk</br>
            <input type="checkbox" class="chb monitorChange" value="Coffee" />Coffee </br>
        </div>
        <select id="comboCar" class="monitorChange">
            <option value="volvo">Volvo</option>
            <option value="saab">Saab</option>
            <option value="mercedes">Mercedes</option>
            <option value="audi">Audi</option>
        </select>
        <button id="testButton">
            test</button><a onclick="NavigateTo()">next >>> </a>

Ich glaube, dass es in diesem Rahmen eine enorme Verbesserung geben kann. Kommentar/Änderungen/Rückmeldungen sind willkommen. :)

0
Savaratkar

Sie können dieses jQuery-Plugin, das ich unter jQuery erstellt habe, auch im Formulare-Plugin verfolgen.

Sehen Sie sich die Demo hier an und laden Sie die JS hier herunter.

0
brokenshard

Wenn Sie für die Verwendung von jQuery offen sind, sehen Sie in meiner Antwort eine ähnliche Frage: Schaltfläche "Abschicken" deaktivieren, sofern sich nicht die ursprünglichen Formulardaten geändert haben .

0
Justin