簡體   English   中英

通過javascript跟蹤表單中的更改的最佳方法是什么?

[英]What is the best way to track changes in a form via javascript?

我想通過javascript跟蹤表單中輸入的變化。 我的意圖是(但不限於)

  • 只有在某些內容發生變化時才啟用“保存”按鈕
  • 如果用戶想要關閉頁面並且未保存某些內容則發出警報

想法?

遍歷所有輸入元素,並在每個元素上放置一個onchange處理程序。 當它觸發時,設置一個標志,讓您知道表單已更改。 它的基本版本很容易設置,但是如果有人將輸入從“a”更改為“b”然后再返回“a”,則不足以識別。 如果抓住那個案件很重要,那么它仍然是可能的,但需要更多的工作。

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

JS中的文本表單元素公開了.value屬性和.defaultValue屬性,因此您可以輕松實現以下內容:

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

對於復選框和單選按鈕,查看element.checked != element.defaultChecked ,對於HTML <select />元素,您需要循環遍歷select.options數組並檢查每個選項是否為selected == defaultSelected

您可能希望使用類似jQuery的框架來將處理程序附加到每個單獨表單元素的onchange事件。 這些處理程序可以調用formChanged()代碼並修改“save”按鈕的enabled屬性,和/或附加/分離文檔正文的beforeunload事件的事件處理程序。

嘗試

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

希望它的幫助))

這是一個用於檢測表單更改的javascript和jquery方法,這很簡單。 它會禁用提交按鈕,直到進行更改。 它通過提交表單以外的方式檢測離開頁面的嘗試。 它由用戶解釋“撤消”,它被封裝在一個功能中以便於應用,並且在提交時不會失敗。 只需調用該函數並傳遞表單的ID即可。

此功能在加載頁面時將表單序列化一次,並在用戶離開頁面之前再次序列化表單。 如果兩個表單狀態不同,則會顯示提示。

嘗試一下: 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');
});

如果您使用的是Web應用程序框架(rails,ASP.NET,Cake,symfony),那么應該有用於ajax驗證的軟件包,

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

和onbeforeunload()上的一些包裝器警告用戶taht即將關閉表單:

http://pragmatig.wordpress.com/2008/03/03/protecting-userdata-from-beeing-lost-with-jquery/ 檢測未保存的更改

我在Ars Technica上回答了類似這樣的問題,但是這個問題被設置為即使用戶沒有模糊文本字段也需要檢測到更改(在這種情況下,更改事件永遠不會觸發)。 我想出了一個全面的腳本:

  1. 如果字段值更改,則啟用提交和重置按鈕
  2. 如果重置表單,則禁用提交和重置按鈕
  3. 如果表單數據已更改且未提交,則中斷離開頁面
  4. 支持IE 6 +,Firefox 2 +,Safari 3+(可能是Opera但我沒有測試)

這個腳本取決於Prototype,但可以很容易地適應另一個庫或獨立。

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

});

我用過dirtyforms.js。 對我來說效果很好。

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

要在關閉之前提醒用戶,請使用unbeforeunload:

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

我會在頁面加載時將每個字段值存儲在變量中,然后在用戶卸載頁面時比較這些值。 如果檢測到任何差異,您將知道要保存的內容並且更好,能夠專門告訴用戶退出時不會保存哪些數據。

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

如果您願意使用jQuery,請參閱我的回答類似的問題: 禁用提交按鈕,除非原始表單數據已更改

將事件處理程序附加到每個表單輸入/ select / textarea的onchange事件。 設置變量以告訴您是否應啟用“保存”按鈕。 創建一個onunload hander來檢查臟表單,並在提交表單時重置變量:

window.onunload = checkUnsavedPage;
var isDirty = false;
var formElements = //Get a reference to all form elements
for(var i = 0; len = formElements.length; i++) {
    //Add onchange event to each element to call formChanged()
}

function formChanged(event) {
    isDirty = false;
    document.getElementById("savebtn").disabled = "";
}

function checkUnsavedPage() {
    if (isDirty) {
        var isSure = confirm("you sure?");  
        if (!isSure) {
            event.preventDefault();
        }
    }
}

以下是Dylan Beattie建議的全面實施:

“未保存數據”保護的客戶端/ JS框架?

您不需要存儲初始值來確定表單是否已更改,除非您在客戶端動態填充它(盡管如此,您仍然可以在表單元素上設置default屬性)。

我遇到了同樣的挑戰,我正在考慮一個共同的解決方案。 下面的代碼並不完美,它來自最初的研發。 以下是我使用的步驟:

1)將以下JS移動到另一個文件(比如changeFramework.js)

2)通過導入將其包含在項目中

3)在你的html頁面中,無論哪個控件都需要監控,添加類“monitorChange”

4)全局變量'hasChanged'將告訴您,如果您正在處理的頁面有任何變化。

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

以下是我使用此框架的控件:

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

我相信這個框架可以有很大的改進。 歡迎提出意見/變更/反饋。 :)

我做了一些跨瀏覽器測試。

在Chrome和Safari上這很不錯:

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

對於Firefox + Chrome / Safari,我這樣做:

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

復選框或單選按鈕等項目需要一個自己的onchange事件監聽器。

您還可以查看我在jQuery跟蹤表單插件中更改的jQuery插件

請在此處查看演示並在此處下載JS

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM