Domanda

Ho l'obbligo di implementare un " Modifiche non salvate " richiesta in un'applicazione ASP .Net. Se un utente modifica i controlli su un modulo Web e tenta di allontanarsi prima di salvare, dovrebbe essere visualizzato un messaggio che avvisa che hanno modifiche non salvate e che offre loro la possibilità di annullare e rimanere nella pagina corrente. Il prompt non dovrebbe essere visualizzato se l'utente non ha toccato nessuno dei controlli.

Idealmente, vorrei implementarlo in JavaScript, ma prima di seguire il mio codice, ci sono framework esistenti o schemi di progettazione consigliati per raggiungere questo obiettivo? Idealmente, vorrei qualcosa che possa essere facilmente riutilizzato su più pagine con modifiche minime.

È stato utile?

Soluzione

Uso di jQuery:

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

Combina con i metodi onunload / onbeforeunload come richiesto.

Dai commenti, i seguenti riferimenti fanno riferimento a tutti i campi di input, senza duplicare il codice:

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

L'uso di $ (": input ") si riferisce a tutti gli elementi di input, textarea, select e button.

Altri suggerimenti

Un pezzo del puzzle:

/**
 * 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;
}

E un altro :

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

Avvolgi tutto e cosa ottieni?

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

Probabilmente vorrai anche cambiare la registrazione del gestore di eventi beforeunload per usare la registrazione degli eventi di LIBRARY_OF_CHOICE .

Nella pagina .aspx, è necessaria una funzione Javascript per dire se le informazioni sul modulo sono o meno "sporche"

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

e nel codebehind, aggiungi i trigger ai campi di input e ripristina i pulsanti di invio / annullamento ....

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

Quanto segue utilizza la funzione onbeforeunload del browser e jquery per acquisire qualsiasi evento onchange. L'IT cerca inoltre qualsiasi pulsante di invio o ripristino per ripristinare il flag che indica che si sono verificati cambiamenti.

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;

Grazie per le risposte a tutti. Ho finito per implementare una soluzione utilizzando JQuery e il Protect-Data . Ciò mi consente di applicare automaticamente il monitoraggio a tutti i controlli in una pagina.

Tuttavia, ci sono alcuni avvertimenti, specialmente quando si ha a che fare con un'applicazione ASP .Net:

  • Quando un utente sceglie l'opzione di annullamento, la funzione doPostBack genererà un errore JavaScript. Ho dovuto mettere manualmente un tentativo-catch intorno alla chiamata .submit all'interno di doPostBack per sopprimerlo.

  • In alcune pagine, un utente potrebbe eseguire un'azione che esegue un postback nella stessa pagina, ma non è un salvataggio. Ciò si traduce in un ripristino della logica JavaScript, quindi pensa che nulla sia cambiato dopo il postback quando qualcosa potrebbe avere. Ho dovuto implementare una casella di testo nascosta che viene postata di nuovo con la pagina e viene utilizzata per contenere un semplice valore booleano che indica se i dati sono sporchi. Questo è persistente in tutti i postback.

  • È possibile che alcuni postback sulla pagina non attivino la finestra di dialogo, ad esempio un pulsante Salva. In questo caso, puoi usare JQuery per aggiungere una funzione OnClick che imposta window.onbeforeunload su null.

Speriamo che questo sia utile per chiunque altro debba implementare qualcosa di simile.

La seguente soluzione funziona con il prototipo (testato in FF, IE 6 e Safari). Utilizza un osservatore di forma generico (che attiva la forma: modificato quando sono stati modificati tutti i campi del modulo), che puoi usare anche per altre cose.

/* 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);

Ecco una soluzione javascript / jquery semplice. Rappresenta " annulla " dall'utente, è incapsulato all'interno di una funzione per facilitare l'applicazione e non si accende in modo errato al momento dell'invio. Basta chiamare la funzione e passare l'ID del modulo.

Questa funzione serializza il modulo una volta quando la pagina viene caricata e di nuovo prima che l'utente lasci la pagina. Se i due stati del modulo sono diversi, viene visualizzato il prompt.

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

Soluzione generale Supporto di più moduli in una determinata pagina ( Copia e incolla il tuo progetto )

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

Nota: questa soluzione è combinata con le soluzioni di altri per creare una soluzione integrata generale.

Caratteristiche:

  • Basta copiare e incollare nella tua app.
  • Supporta moduli multipli.
  • Puoi modellare o rendere le azioni forme sporche, dal momento che hanno la classe " form-dirty " ;.
  • Puoi escludere alcuni moduli aggiungendo la classe 'ignore-changes'.

Di recente ho contribuito a un plug-in jQuery open source chiamato dirtyForms .

Il plug-in è progettato per funzionare con HTML aggiunto in modo dinamico, supporta più moduli, può supportare praticamente qualsiasi framework di dialogo, ricade nella finestra di dialogo del browser prima dello scaricamento, ha un framework helper collegabile per supportare lo stato sporco dagli editor personalizzati (un plug-in tinyMCE è incluso), funziona all'interno di iFrames e lo stato sporco può essere impostato o ripristinato a piacimento.

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

Rilevare le modifiche ai moduli con l'utilizzo di jQuery è molto semplice:

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

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

Ho ampliato il suggerimento di Slace sopra, per includere la maggior parte degli elementi modificabili e anche escludere determinati elementi (con uno stile CSS chiamato "ricerca sr" qui) dall'impostazione della bandiera sporca.

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

      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;

Questo è esattamente ciò che il plugin Fleegix.js fleegix.form.diff ( http://js.fleegix.org/plugins/form/diff ) è stato creato per. Serializza lo stato iniziale del modulo in caricamento utilizzando fleegix.form.toObject ( http://js.fleegix.org/ref#fleegix .form.toObject ) e salvalo in una variabile, quindi confronta con lo stato corrente usando fleegix.form.diff allo scarico. Facile come una torta.

Un metodo , utilizzando array per contenere le variabili in modo da poter tracciare le modifiche.

Ecco un metodo molto semplice per rilevare le modifiche , ma il resto non è così elegante.

Un altro metodo abbastanza semplice e piccolo, da Blog Farfetched :

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

In IE document. già non funzionerà correttamente aggiornerà i valori di input.

quindi dobbiamo associare l'evento load all'interno della funzione document.ready che gestirà anche per il browser IE.

sotto è il codice che dovresti inserire nella funzione document.ready.

 $(document).ready(function () {
   $(window).bind("load", function () { 
    $("input, select").change(function () {});
   });
});
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top