Eu tenho um formulário html com guias. Ao navegar de uma guia para outra, os dados da guia atual são persistidos (no banco de dados) mesmo que não haja alteração nos dados.
Gostaria de fazer a chamada de persistência apenas se o formulário for editado. O formulário pode conter qualquer tipo de controle. Sujar o formulário não precisa ser digitando algum texto, mas a escolha de uma data em um controle de calendário também se qualifica.
Uma maneira de conseguir isso seria exibir o formulário no modo somente leitura por padrão e ter um botão 'Editar' e se o usuário clicar no botão editar, então a chamada para DB é feita (mais uma vez, independentemente de os dados serem modificados . Esta é uma melhoria melhor em relação ao que existe atualmente).
Gostaria de saber como escrever uma função javascript genérica que verificaria se algum dos valores dos controles foi modificado?
fonte
Respostas:
Em javascript puro, isso não seria uma tarefa fácil, mas jQuery torna muito fácil de fazer:
$("#myform :input").change(function() { $("#myform").data("changed",true); });
Então, antes de salvar, você pode verificar se foi alterado:
if ($("#myform").data("changed")) { // submit the form }
No exemplo acima, o formulário tem um id igual a "myform".
Se você precisar disso de várias formas, pode facilmente transformá-lo em um plug-in:
$.fn.extend({ trackChanges: function() { $(":input",this).change(function() { $(this.form).data("changed", true); }); } , isChanged: function() { return this.data("changed"); } });
Então você pode simplesmente dizer:
$("#myform").trackChanges();
e verifique se um formulário foi alterado:
if ($("#myform").isChanged()) { // ... }
fonte
trackChanges: function () { $(document).on('change', $(this).find(':input'), function (e) { var el = $(e.target); $(el).closest('form').data("changed", true); });
Caso o JQuery esteja fora de questão. Uma rápida pesquisa no Google encontrou implementações Javascript de algoritmos de hash MD5 e SHA1. Se você quiser, pode concatenar todas as entradas do formulário e fazer um hash delas e, em seguida, armazenar esse valor na memória. Quando o usuário terminar. Concatene todos os valores e hash novamente. Compare os 2 hashes. Se forem iguais, o usuário não alterou nenhum campo do formulário. Se forem diferentes, algo foi editado e você precisa chamar seu código de persistência.
fonte
Não tenho certeza se entendi bem sua pergunta, mas e o addEventListener? Se você não se preocupa muito com o suporte do IE8, não há problema. O código a seguir está funcionando para mim:
var form = document.getElementById("myForm"); form.addEventListener("input", function () { console.log("Form has changed!"); });
fonte
Outra maneira de conseguir isso é serializar o formulário:
$(function() { var $form = $('form'); var initialState = $form.serialize(); $form.submit(function (e) { if (initialState === $form.serialize()) { console.log('Form is unchanged!'); } else { console.log('Form has changed!'); } e.preventDefault(); }); });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <form> Field 1: <input type="text" name="field_1" value="My value 1"> <br> Field 2: <input type="text" name="field_2" value="My value 2"> <br> Check: <input type="checkbox" name="field_3" value="1"><br> <input type="submit"> </form>
fonte
serialize()
se de que não incluirádisabled
elementos. Pode ser bom para muitos casos, mas pode ser um problema em outros casos.Veja como eu fiz (sem usar jQuery).
No meu caso, eu queria que um elemento específico do formulário não fosse contado, porque foi o elemento que acionou a verificação e, portanto, sempre terá mudado. O elemento excepcional é denominado 'reporting_period' e é codificado na função 'hasFormChanged ()'.
Para testar, faça com que um elemento chame a função "changeReportingPeriod ()", que você provavelmente vai querer dar outro nome.
IMPORTANTE: Você deve chamar setInitialValues () quando os valores forem definidos para seus valores originais (normalmente no carregamento da página, mas não no meu caso).
NOTA: Não afirmo que esta seja uma solução elegante, na verdade não acredito em soluções JavaScript elegantes. Minha ênfase pessoal no JavaScript está na legibilidade, não na elegância estrutural (como se isso fosse possível no JavaScript). Não me preocupo com o tamanho do arquivo ao escrever JavaScript porque é para isso que serve o gzip, e tentar escrever um código JavaScript mais compacto invariavelmente leva a problemas intoleráveis de manutenção. Não peço desculpas, não expresso remorso e me recuso a debatê-lo. É JavaScript. Desculpe, eu tive que deixar isso claro para me convencer de que deveria me preocupar em postar. Seja feliz! :)
var initial_values = new Array(); // Gets all form elements from the entire document. function getAllFormElements() { // Return variable. var all_form_elements = Array(); // The form. var form_activity_report = document.getElementById('form_activity_report'); // Different types of form elements. var inputs = form_activity_report.getElementsByTagName('input'); var textareas = form_activity_report.getElementsByTagName('textarea'); var selects = form_activity_report.getElementsByTagName('select'); // We do it this way because we want to return an Array, not a NodeList. var i; for (i = 0; i < inputs.length; i++) { all_form_elements.push(inputs[i]); } for (i = 0; i < textareas.length; i++) { all_form_elements.push(textareas[i]); } for (i = 0; i < selects.length; i++) { all_form_elements.push(selects[i]); } return all_form_elements; } // Sets the initial values of every form element. function setInitialFormValues() { var inputs = getAllFormElements(); for (var i = 0; i < inputs.length; i++) { initial_values.push(inputs[i].value); } } function hasFormChanged() { var has_changed = false; var elements = getAllFormElements(); for (var i = 0; i < elements.length; i++) { if (elements[i].id != 'reporting_period' && elements[i].value != initial_values[i]) { has_changed = true; break; } } return has_changed; } function changeReportingPeriod() { alert(hasFormChanged()); }
fonte
As alterações de formulário podem ser facilmente detectadas em JavaScript nativo sem jQuery:
function initChangeDetection(form) { Array.from(form).forEach(el => el.dataset.origValue = el.value); } function formHasChanges(form) { return Array.from(form).some(el => 'origValue' in el.dataset && el.dataset.origValue !== el.value); }
initChangeDetection()
pode ser chamado com segurança várias vezes ao longo do ciclo de vida de sua página: Consulte Teste em JSBinPara navegadores mais antigos que não suportam funções de seta / array mais recentes:
function initChangeDetection(form) { for (var i=0; i<form.length; i++) { var el = form[i]; el.dataset.origValue = el.value; } } function formHasChanges(form) { for (var i=0; i<form.length; i++) { var el = form[i]; if ('origValue' in el.dataset && el.dataset.origValue !== el.value) { return true; } } return false; }
fonte
Aqui está uma demonstração do método polyfill em JavaScript nativo que usa a
FormData()
API para detectar entradas de formulário criadas, atualizadas e excluídas. Você pode verificar se algo foi alterado usandoHTMLFormElement#isChanged
e obter um objeto contendo as diferenças de um formulário de redefinição usandoHTMLFormElement#changes
(presumindo que não estejam mascarados por um nome de entrada):Object.defineProperties(HTMLFormElement.prototype, { isChanged: { configurable: true, get: function isChanged () { 'use strict' var thisData = new FormData(this) var that = this.cloneNode(true) // avoid masking: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/reset HTMLFormElement.prototype.reset.call(that) var thatData = new FormData(that) const theseKeys = Array.from(thisData.keys()) const thoseKeys = Array.from(thatData.keys()) if (theseKeys.length !== thoseKeys.length) { return true } const allKeys = new Set(theseKeys.concat(thoseKeys)) function unequal (value, index) { return value !== this[index] } for (const key of theseKeys) { const theseValues = thisData.getAll(key) const thoseValues = thatData.getAll(key) if (theseValues.length !== thoseValues.length) { return true } if (theseValues.some(unequal, thoseValues)) { return true } } return false } }, changes: { configurable: true, get: function changes () { 'use strict' var thisData = new FormData(this) var that = this.cloneNode(true) // avoid masking: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/reset HTMLFormElement.prototype.reset.call(that) var thatData = new FormData(that) const theseKeys = Array.from(thisData.keys()) const thoseKeys = Array.from(thatData.keys()) const created = new FormData() const deleted = new FormData() const updated = new FormData() const allKeys = new Set(theseKeys.concat(thoseKeys)) function unequal (value, index) { return value !== this[index] } for (const key of allKeys) { const theseValues = thisData.getAll(key) const thoseValues = thatData.getAll(key) const createdValues = theseValues.slice(thoseValues.length) const deletedValues = thoseValues.slice(theseValues.length) const minLength = Math.min(theseValues.length, thoseValues.length) const updatedValues = theseValues.slice(0, minLength).filter(unequal, thoseValues) function append (value) { this.append(key, value) } createdValues.forEach(append, created) deletedValues.forEach(append, deleted) updatedValues.forEach(append, updated) } return { created: Array.from(created), deleted: Array.from(deleted), updated: Array.from(updated) } } } }) document.querySelector('[value="Check"]').addEventListener('click', function () { if (this.form.isChanged) { console.log(this.form.changes) } else { console.log('unchanged') } })
<form> <div> <label for="name">Text Input:</label> <input type="text" name="name" id="name" value="" tabindex="1" /> </div> <div> <h4>Radio Button Choice</h4> <label for="radio-choice-1">Choice 1</label> <input type="radio" name="radio-choice-1" id="radio-choice-1" tabindex="2" value="choice-1" /> <label for="radio-choice-2">Choice 2</label> <input type="radio" name="radio-choice-2" id="radio-choice-2" tabindex="3" value="choice-2" /> </div> <div> <label for="select-choice">Select Dropdown Choice:</label> <select name="select-choice" id="select-choice"> <option value="Choice 1">Choice 1</option> <option value="Choice 2">Choice 2</option> <option value="Choice 3">Choice 3</option> </select> </div> <div> <label for="textarea">Textarea:</label> <textarea cols="40" rows="8" name="textarea" id="textarea"></textarea> </div> <div> <label for="checkbox">Checkbox:</label> <input type="checkbox" name="checkbox" id="checkbox" /> </div> <div> <input type="button" value="Check" /> </div> </form>
fonte