Подтвердить что ты не робот

Каков наилучший способ отслеживания изменений в форме через javascript?

Я хочу отслеживать изменения в входах в форме через javascript. Мое намерение состоит (но не ограничивается) в

  • включить кнопку "Сохранить" только тогда, когда что-то изменилось.
  • предупреждение, если пользователь хочет закрыть страницу и что-то не сохраняется

Идеи?

4b9b3361

Ответ 1

Прокрутите все входные элементы и поместите на них обработчик onchange. Когда это срабатывает, установите флаг, который позволяет вам узнать, что форма изменилась. Базовая версия этого будет очень проста в настройке, но не будет достаточно умна, чтобы узнать, изменил ли кто-то вход от "a" до "b", а затем вернулся к "a". Если бы было важно поймать этот случай, тогда это было бы возможно, но потребовалось бы немного больше работы.

Вот базовый пример в jQuery:

$("#myForm")
    .on("change", ":input", function() {
        // do whatever you need to do when something changed.
        // perhaps set up an onExit function on the window
        $('#saveButton').show();
    })
;

Ответ 2

Элементы текстовой формы в 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() и изменить свойство enabled вашей кнопки "Сохранить" и/или прикрепить/отсоединить обработчик событий для события .

Ответ 3

Try

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

Надеюсь, что это поможет))

Ответ 4

Здесь javascript и jquery метод для обнаружения изменений формы, который является простым. Он отключает кнопку отправки до тех пор, пока не будут сделаны изменения. Он обнаруживает попытки покинуть страницу средствами, отличными от отправки формы. Он учитывает "отмену" пользователя, он инкапсулирован в функцию для удобства приложения, и он не пропускает пропуски при отправке. Просто вызовите функцию и передайте идентификатор вашей формы.

Эта функция сериализует форму один раз, когда страница загружается, и снова, прежде чем пользователь покинет страницу. Если два состояния формы различны, отображается приглашение.

Попробуйте: 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');
});

Ответ 5

Если вы используете инфраструктуру веб-приложений (рельсы, ASP.NET, Cake, symfony), должны быть пакеты для проверки ajax,

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

и некоторая оболочка onbeforeunload(), чтобы предупредить пользователей, что они закрывают форму:

http://pragmatig.wordpress.com/2008/03/03/protecting-userdata-from-beeing-lost-with-jquery/ Обнаружение несохраненных изменений

Ответ 6

Я ответил на такой вопрос на Ars Technica, но вопрос был обрамлен таким образом, что изменения должны были быть обнаружены, даже если пользователь не размывает текстовое поле (в этом случае событие изменения никогда не срабатывает). Я придумал всеобъемлющий script который:

  • позволяет отправлять и reset кнопки, если значения поля меняются
  • отключает кнопки submit и reset, если форма reset
  • прерывает выход из страницы, если данные формы были изменены и не были отправлены
  • поддерживает IE 6+, Firefox 2+, Safari 3+ (и, предположительно, Opera, но я не тестировал)

Этот script зависит от прототипа, но может быть легко адаптирован к другой библиотеке или автономно.

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

});

Ответ 7

Чтобы предупредить пользователя перед закрытием, используйте unbeforeunload:

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

Ответ 8

Я бы сохранил каждое значение поля в переменной при загрузке страницы, а затем сравним эти значения, когда пользователь выгружает страницу. Если обнаружены какие-либо различия, вы будете знать, что сохранить и еще лучше, сможете указать пользователю, какие данные не будут сохранены, если они выйдут.

// this example uses the prototype library
// also, it 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;
});

Ответ 10

Прикрепите обработчик событий к каждому событию ввода /select/textarea формы. Установка переменной, чтобы сообщить вам, следует ли включить кнопку "Сохранить". Создайте обработчик onunload, который также проверяет грязную форму, и когда форма отправляется reset переменная:

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

Ответ 11

Здесь полная реализация предложения Дилана Битти:

Клиент /JS Framework для "Несохраненных данных" Защита?

Вам не нужно сохранять начальные значения, чтобы определить, изменилась ли форма, если вы не динамически ее заполняете на стороне клиента (хотя даже тогда вы все равно можете настроить свойства default в форме элементы).

Ответ 14

У меня был такой же вызов, и я думал об общем решении. Код ниже не идеален, его от начального r & d. Ниже приведены шаги, которые я использовал:

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>

Я считаю, что в этой структуре может быть значительное улучшение. Комментарий/Изменения/отзывы приветствуются.:)

Ответ 15

Я проверил несколько Cross Browser Testing.

В Chrome и Safari это приятно:

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

Для Firefox + Chrome/Safari я использую это:

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

Элементы, такие как флажки или радиолюбители, нуждаются в собственном прослушивателе событий onchange.