Question

Je souhaite implémenter un " Modifications non enregistrées " invite dans une application ASP .Net. Si un utilisateur modifie les contrôles d'un formulaire Web et tente de s'éloigner avant l'enregistrement, une invite doit s'afficher pour les avertir qu'ils ont des modifications non enregistrées et leur donner la possibilité d'annuler et de rester sur la page en cours. L’invite ne doit pas s’afficher si l’utilisateur n’a touché à aucun des contrôles.

Idéalement, j'aimerais implémenter cela en JavaScript, mais avant de lancer mon propre code, existe-t-il des cadres existants ou des modèles de conception recommandés pour y parvenir? Idéalement, j'aimerais quelque chose qui puisse être facilement réutilisé sur plusieurs pages avec un minimum de modifications.

Était-ce utile?

La solution

Utilisation de jQuery:

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

Combinez avec les méthodes onunload / onbeforeunload selon vos besoins.

À partir des commentaires, les éléments suivants font référence à tous les champs de saisie, sans dupliquer le code:

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

L'utilisation de $ (": input ") fait référence à tous les éléments input, textarea, select et button.

Autres conseils

Une pièce du 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;
}

Et un autre :

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

Enveloppez le tout et qu'obtenez-vous?

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

Vous voudrez probablement aussi modifier l'enregistrement du gestionnaire d'événements beforeunload pour utiliser l'enregistrement d'événement de LIBRARY_OF_CHOICE .

Dans la page .aspx, vous avez besoin d'une fonction Javascript pour indiquer si les informations de formulaire sont ou non "sales".

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

et dans le code ci-dessous, ajoutez les déclencheurs aux champs de saisie et réinitialisez les boutons de soumission / annulation ....

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

Ce qui suit utilise la fonction onbeforeunload du navigateur et jquery pour capturer tout événement onchange. Le service informatique recherche également des boutons d'envoi ou de réinitialisation pour réinitialiser l'indicateur indiquant que des modifications ont eu lieu.

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;

Merci à tous pour les réponses. J'ai fini par implémenter une solution à l'aide de JQuery et du plug-in Protect-Data . Cela me permet d'appliquer automatiquement la surveillance à tous les contrôles d'une page.

Cependant, il existe quelques réserves, en particulier lorsqu'il s'agit d'une application ASP .Net:

  • Lorsqu'un utilisateur choisit l'option d'annulation, la fonction doPostBack génère une erreur JavaScript. Je devais manuellement mettre un try-catch sur l'appel .submit dans doPostBack pour le supprimer.

  • Sur certaines pages, un utilisateur peut effectuer une action effectuant une publication sur la même page, mais sans enregistrer. Il en résulte une réinitialisation de la logique JavaScript, ce qui signifie que rien n'a changé après la publication lorsque quelque chose est susceptible de se produire. J'ai dû implémenter une zone de texte masquée qui est postée avec la page et qui est utilisée pour contenir une simple valeur booléenne indiquant si les données sont sales. Cela persiste dans les publications.

  • Vous pouvez souhaiter que certaines publications sur la page ne déclenchent pas la boîte de dialogue, telle qu'un bouton Enregistrer. Dans ce cas, vous pouvez utiliser JQuery pour ajouter une fonction OnClick qui définit la valeur window.onbeforeunload sur null.

J'espère que cela sera utile à quiconque devra mettre en œuvre quelque chose de similaire.

La solution suivante fonctionne pour le prototype (testé dans FF, IE 6 et Safari). Il utilise un observateur de formulaire générique (qui déclenche le formulaire: modifié lorsque des champs du formulaire ont été modifiés), que vous pouvez également utiliser pour d’autres éléments.

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

Voici une solution javascript / jquery simple. Cela représente & und; undos " par l'utilisateur, il est encapsulé dans une fonction pour faciliter l'application, et ne provoque pas de ratés lors de la soumission. Appelez simplement la fonction et transmettez l'ID de votre formulaire.

Cette fonction sérialise le formulaire une fois lorsque la page est chargée et à nouveau avant que l'utilisateur ne quitte la page. Si les deux états du formulaire sont différents, l’invite s’affiche.

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

Solution générale: prise en charge de plusieurs formulaires dans une page donnée ( copiez et collez dans votre projet )

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

Remarque: cette solution est combinée à d'autres solutions pour créer une solution intégrée globale.

Caractéristiques:

  • Il suffit de copier et coller dans votre application.
  • Prend en charge plusieurs formulaires.
  • Vous pouvez styler ou créer des actions avec des formulaires sales, car ils ont la classe "form-dirty".
  • Vous pouvez exclure certains formulaires en ajoutant la classe 'ignore-changes'.

J'ai récemment contribué à un plug-in jQuery open source appelé dirtyForms .

Le plug-in est conçu pour fonctionner avec du code HTML ajouté dynamiquement, prend en charge plusieurs formulaires, peut prendre en charge pratiquement tous les cadres de dialogue, revient au dialogue avant le téléchargement du navigateur, dispose d'un framework d'assistance pluggable permettant de récupérer le statut modifié des éditeurs personnalisés (un plugin tinyMCE est inclus), fonctionne dans iFrames et le statut modifié peut être défini ou réinitialisé à volonté.

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

Détecter les modifications de formulaire à l’aide de jQuery est très simple:

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

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

J'ai développé la suggestion de Slace ci-dessus, pour inclure la plupart des éléments éditables et exclure également certains éléments (avec un style CSS appelé "srSearch" ici) de provoquer la définition de l'indicateur "sale".

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

C’est exactement ce que le plugin Fleegix.js fleegix.form.diff ( http://js.fleegix.org/plugins/form/diff ) a été créé pour. Sérialisez l'état initial du formulaire au chargement à l'aide de fleegix.form.toObject ( http://js.fleegix.org/ref#fleegix .form.toObject ) et enregistrez-le dans une variable, puis comparez-le avec l'état actuel à l'aide de fleegix.form.diff lors du déchargement. Facile comme bonjour.

Une méthode , utilisant des tableaux pour stocker les variables afin de suivre les modifications.

Voici une méthode très simple pour détecter les modifications , mais le reste n'est pas aussi élégant. / p>

Une autre méthode relativement simple et petite, à partir de Blog fouillé :

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

Dans IE, document.ready ne fonctionnera pas correctement, il mettra à jour les valeurs d'entrée.

nous devons donc lier l'événement load à l'intérieur de la fonction document.ready qui gérera également le navigateur IE.

ci-dessous est le code que vous devez insérer dans la fonction document.ready.

 $(document).ready(function () {
   $(window).bind("load", function () { 
    $("input, select").change(function () {});
   });
});
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top