97

ASP.Netアプリケーションに「未保存の変更」プロンプトを実装する必要があります。ユーザーがWebフォームのコントロールを変更し、保存する前に移動しようとすると、未保存の変更があることを警告するプロンプトが表示され、キャンセルして現在のページにとどまるオプションが表示されます。ユーザーがどのコントロールにも触れていない場合、プロンプトは表示されません。

理想的にはこれをJavaScriptで実装したいのですが、自分のコードをローリングする前に、これを実現するための既存のフレームワークまたは推奨されるデザインパターンはありますか?理想的には、最小限の変更で複数のページで簡単に再利用できるものが欲しいです。

4

16 に答える 16

98

jQuery の使用:

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

onunload必要に応じて/onbeforeunloadメソッドと組み合わせます。

コメントから、以下はコードを複製することなく、すべての入力フィールドを参照します。

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

Using$(":input")は、input、textarea、select、および button のすべての要素を指します。

于 2008-10-01T01:26:36.953 に答える
47

パズルのピース:

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

そして別

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

すべてをまとめると、何が得られますか?

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

beforeunloadのイベント登録を使用するように、イベント ハンドラーの登録も変更する必要があるでしょうLIBRARY_OF_CHOICE

于 2008-10-01T01:09:46.557 に答える
17

.aspxページでは、フォーム情報が「ダーティ」であるかどうかを判断するためのJavascript関数が必要です。

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

コードビハインドで、入力フィールドにトリガーを追加し、送信/キャンセルボタンをリセットします。

btnSubmit.Attributes.Add("onclick", "isDirty = 0;");
btnCancel.Attributes.Add("onclick", "isDirty = 0;");
txtName.Attributes.Add("onchange", "setDirty();");
txtAddress.Attributes.Add("onchange", "setDirty();");
//etc..
于 2008-10-01T00:51:45.557 に答える
9

以下では、ブラウザの onbeforeunload 関数と jquery を使用して、onchange イベントをキャプチャします。IT は、変更が発生したことを示すフラグをリセットするための送信ボタンまたはリセット ボタンも探します。

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;
于 2009-11-16T19:35:06.747 に答える
8

返信ありがとうございます。最終的に、JQuery とProtect-Dataプラグインを使用してソリューションを実装しました。これにより、ページ上のすべてのコントロールに監視を自動的に適用できます。

ただし、特に ASP .Net アプリケーションを扱う場合は、いくつかの注意事項があります。

  • ユーザーがキャンセル オプションを選択すると、doPostBack 関数は JavaScript エラーをスローします。それを抑制するには、doPostBack 内の .submit 呼び出しの周りに手動で try-catch を配置する必要がありました。

  • 一部のページでは、ユーザーは同じページへのポストバックを実行するアクションを実行できますが、保存はできません。これにより、JavaScript ロジックがリセットされるため、何かが変更された可能性がある場合でも、ポストバック後に何も変更されていないと見なされます。ページと共にポストバックされ、データがダーティかどうかを示す単純なブール値を保持するために使用される非表示のテキスト ボックスを実装する必要がありました。これは、ポストバック間で保持されます。

  • [保存] ボタンなど、ページ上の一部のポストバックがダイアログをトリガーしないようにする場合があります。この場合、JQuery を使用して、window.onbeforeunload を null に設定する OnClick 関数を追加できます。

うまくいけば、これは同様のものを実装しなければならない他の人に役立ちます.

于 2008-10-01T23:45:27.657 に答える
7

特定のページで複数のフォームをサポートする一般的な解決策 (プロジェクトにコピーして貼り付けるだけです)

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

注: このソリューションは、他のソリューションを組み合わせて、一般的な統合ソリューションを作成します。

特徴:

  • コピーしてアプリに貼り付けるだけです。
  • 複数のフォームをサポートします。
  • アクションには "form-dirty" クラスがあるため、スタイルを設定したり、アクションをダーティ フォームにすることができます。
  • クラス「ignore-changes」を追加することで、一部のフォームを除外できます。
于 2015-05-21T12:57:01.500 に答える
6

次のソリューションは、プロトタイプで機能します (FF、IE 6、および Safari でテスト済み)。これは一般的なフォーム オブザーバー (フォームのフィールドが変更されたときに form:changed を起動する) を使用し、他のものにも使用できます。

/* 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);
于 2009-05-25T09:17:48.333 に答える
6

シンプルなjavascript / jqueryソリューションを次に示します。ユーザーによる「取り消し」を考慮し、アプリケーションを簡単にするために関数内にカプセル化され、送信時に誤作動しません。関数を呼び出して、フォームの ID を渡すだけです。

この関数は、ページがロードされたときにフォームを 1 回シリアライズし、ユーザーがページを離れる前にもう一度シリアライズします。2 つのフォームの状態が異なる場合、プロンプトが表示されます。

試してみてください: 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');
});
于 2013-10-22T18:36:34.783 に答える
4

jQuery を使用してフォームの変更を検出するのは非常に簡単です。

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

// check for form changes
if ($('#formId').serialize() != formInitVal) {
    // show confirmation alert
}
于 2014-12-15T10:48:19.390 に答える
4

最近、 dirtyFormsというオープン ソースの jQuery プラグインに貢献しました。

プラグインは、動的に追加された HTML で動作するように設計されており、複数のフォームをサポートし、実質的にすべてのダイアログ フレームワークをサポートでき、アンロード ダイアログの前にブラウザーにフォールバックし、カスタム エディターからのダーティ ステータスの取得をサポートするプラグ可能なヘルパー フレームワークを備えています (tinyMCE プラグインが含まれています)。 、iFrames 内で動作し、ダーティ ステータスを自由に設定またはリセットできます。

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

于 2012-04-30T19:35:46.393 に答える
2

上記の Slace の提案を拡張して、ほとんどの編集可能な要素を含め、特定の要素 (ここでは「srSearch」と呼ばれる CSS スタイル) を除外して、ダーティ フラグが設定されるようにしました。

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

于 2012-02-14T05:17:24.780 に答える
1

これはまさに Fleegix.js プラグインfleegix.form.diff(http://js.fleegix.org/plugins/form/diff ) 用に作成されました。fleegix.form.toObject(を使用して、ロード時にフォームの初期状態をシリアル化します。http://js.fleegix.org/ref#fleegix.form.toObjectfleegix.form.diff ) を使用して変数に保存し、 on unloadを使用して現在の状態と比較します。やさしい。

于 2008-10-02T01:32:28.677 に答える
0

1つの方法は、配列を使用して変数を保持し、変更を追跡できるようにする方法です。

これは変更を検出するための非常に簡単な方法ですが、残りはそれほどエレガントではありません。

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>
于 2008-10-01T00:56:05.717 に答える