97 votes

Détection des modifications non sauvegardées

J'ai besoin de mettre en œuvre une invite "Modifications non sauvegardées" dans une application ASP .Net. Si un utilisateur modifie les contrôles d'un formulaire Web et tente de quitter la page avant de l'enregistrer, une invite doit s'afficher pour l'avertir que les modifications n'ont pas été enregistrées et lui 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 mettre en œuvre ce système en JavaScript, mais avant de m'engager sur la voie du développement de mon propre code, existe-t-il des frameworks existants ou des modèles de conception recommandés pour y parvenir ? Idéalement, je voudrais quelque chose qui puisse être facilement réutilisé sur plusieurs pages avec un minimum de modifications.

0 votes

Je suis intéressé par la même chose, mais pas pour asp.net, mais je pense qu'il existe une solution générale.

0 votes

La solution que j'ai postée ci-dessous peut être utilisée en HTML/Javscript simple. Il suffit de remplacer le "codebehind" par des attributs dans les balises HTML elles-mêmes.

0 votes

Je sais que j'ai 5 ans de retard ici, mais je pense que je peux améliorer les solutions précédentes... Je viens de corriger et mettre à jour ma réponse ci-dessous.

100voto

Aaron Powell Points 15598

Utilisation de jQuery :

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

Combinez avec onunload / onbeforeunload selon les besoins.

A partir des commentaires, ce qui suit référence tous les champs de saisie, sans dupliquer le code :

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

Utilisation de $(":input") fait référence à tous les éléments de saisie, de zone de texte, de sélection et de bouton.

33 votes

Upvote parce que j'ai utilisé cette solution mais il y a un moyen légèrement plus facile. Si vous utilisez : $(':input').change(function () { alors cela fonctionne pour tous les champs de saisie, vous n'avez pas besoin de reproduire pour les autres types de saisie. $(":input") sélectionne tous les éléments de type input, textarea, select et button.

5 votes

Je pense que cela peut avoir des problèmes dans Firefox. Si un utilisateur modifie le formulaire, puis clique sur le bouton Rafraîchir du navigateur, la page sera rechargée et Firefox remplira le formulaire avec les entrées précédentes de l'utilisateur - sans déclencher l'événement de modification. Maintenant, le formulaire sera sale, mais le drapeau ne sera pas activé à moins que l'utilisateur ne fasse une autre modification.

9 votes

Un petit conseil. Si le formulaire est sale, cela ne signifie pas pour autant qu'il contient des données réellement modifiées. Pour une meilleure utilisation, vous devez comparer les anciennes données avec les nouvelles ;)

47voto

insin Points 19509

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

Emballez tout ça, et qu'est-ce que vous obtenez ?

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 de la fonction beforeunload pour utiliser le gestionnaire d'événement LIBRARY_OF_CHOICE de l'événement.

0 votes

Dans Firefox 9.0.1, je n'obtiens aucun message. J'ai un message par défaut qui dit "Êtes-vous sûr de vouloir quitter la page ? Certaines données pourraient être perdues" (il s'agit plus ou moins de la traduction du message que mon navigateur non anglophone m'affiche).

1 votes

Ce script est génial, mais pour moi il a aussi affiché le message d'avertissement lors de la soumission de mon formulaire. J'ai corrigé cela en déliant l'événement dans un onClick ( onclick="window.onbeforeunload=null" )

1 votes

J'aime l'approche qui consiste à comparer les propriétés defaultValue etc. plutôt que de définir un bit sale. Cela signifie que si quelqu'un modifie un champ, puis le modifie à nouveau, le formulaire ne sera pas considéré comme sale.

17voto

Wayne Points 12304

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

<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 codebehind, ajoutez les déclencheurs aux champs de saisie ainsi que les réinitialisations sur 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..

9voto

Colin Houghton Points 71

La méthode suivante utilise la fonction onbeforeunload du navigateur et jquery pour capturer tout événement onchange. Il recherche également les boutons d'envoi ou de réinitialisation pour réinitialiser le drapeau indiquant que des modifications ont été apportées.

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;

0 votes

Bonjour colin, la réinitialisation n'a pas fonctionné lorsque j'ai placé une case à cocher, initialement je l'ai cochée et décochée à nouveau mais l'alerte a été déclenchée, comment puis-je réinitialiser lorsque l'utilisateur a décoché la case à cocher ?

8voto

tbreffni Points 3031

Merci à tous pour les réponses. J'ai fini par mettre en place une solution en utilisant JQuery et la fonction Protect-Data plug-in. Cela me permet d'appliquer automatiquement la surveillance à tous les contrôles d'une page.

Il y a toutefois quelques réserves à faire, surtout lorsqu'il s'agit d'une application ASP .Net :

  • Lorsqu'un utilisateur choisit l'option d'annulation, la fonction doPostBack déclenche une erreur JavaScript. J'ai dû placer manuellement un try-catch autour de l'appel .submit dans doPostBack pour le supprimer.

  • Sur certaines pages, un utilisateur peut effectuer une action qui entraîne un retour à la même page, mais qui n'est pas une sauvegarde. Cela entraîne une réinitialisation de la logique JavaScript, qui pense alors que rien n'a changé après le retour à la page, alors que c'est peut-être le cas. J'ai dû implémenter une zone de texte cachée qui est renvoyée avec la page, et qui est utilisée pour contenir une simple valeur booléenne indiquant si les données sont sales. Cette valeur est conservée pour tous les retours en arrière.

  • Vous pouvez souhaiter que certains retours sur la page ne déclenchent pas la boîte de dialogue, comme un bouton Enregistrer. Dans ce cas, vous pouvez utiliser JQuery pour ajouter une fonction OnClick qui donne la valeur null à window.onbeforeunload.

J'espère que ces informations seront utiles à toute personne qui devra mettre en œuvre quelque chose de similaire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X