How to count state changes in fields with a certain class within a function?

Asked

Viewed 162 times

6

How do I count how many changes occur in all fields of a form with a certain class?

Update: What I want to know is if there has been any change in each field (one), and not how many times there was change in each field (even if the user changes the option, it counts only as once - the first...). In short, only how many fields with the class in question have been modified once (at least).

For example:

$("select, input").one('change', function () {

    var totalSelect = $('select').length;
    var totalInputs = $('input').length;
    var ocultosOuOpcionais = $('.ocultosOuOpcionais').length;
    var ocultosOuOpcionaisMudados = ?????
    var total = (totalInputs + totalSelect + ocultosOuOpcionaisMudados) - ocultosOuOpcionais;
});

Every time there is a change of state in some of the fields with the class .ocultosOuOpcionais, want to update the variable ocultosOuOpcionaisMudados. How can I do that?

2 answers

2


You can use data-Attributes to "store" the element state. For example, having an element (input, select, textarea) with the attribute data-foi-modificado:

<input type='text' data-foi-modificado />

And with Jquery you can change this property:

$('input').one('change', function(){
  $(this).data('foi-modificado', true);
});

Later you can make a filter or use the selector itself to get only the elements that are with foi-modificado = "true". Here is an example testing some elements:

$(function(){

  // Quando houver mudança ou perder o foco, o atributo 'foi-modificado'
  // passará a ter valor 'true'.
  $('.ocultosOuOpcionais').one('change', function(){
  	$(this).data('foi-modificado', true);
  });


  $('button').on('click', function(){
	// Filtrando todos em que 'foi-modificado' é true.
    var modificados = $('.ocultosOuOpcionais').filter(function(){
  	  return $(this).data('foi-modificado');
    });
  
    var mensagem = 'Modificados: ';
    modificados.each(function(indice, elemento){
  	  mensagem += $(elemento).prop('name') + ', ';
    });
    alert(mensagem);
  });
});
span { display: inline-block; width: 100% }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<span>
  1. <input class='ocultosOuOpcionais' type='text' name='1' data-foi-modificado/>
</span>

<span>
  2. <input class='ocultosOuOpcionais' type='number' name='2' data-foi-modificado/>
</span>

<span>
  3. <input class='ocultosOuOpcionais' type='color' name='3' data-foi-modificado/>
</span>

<span>
  4. <input class='ocultosOuOpcionais' type='tel' name='4' data-foi-modificado/>
</span>

<span>
  5. <select class='ocultosOuOpcionais' name='5' data-foi-modificado>
    <option selected>A</option>
    <option>B</option>
  </select>
</span>

<span>
  6. <input class='ocultosOuOpcionais' type='radio' name='6' data-foi-modificado/>
</span>

<span>
  7. <input class='ocultosOuOpcionais' type='checkbox' name='7' data-foi-modificado/>
</span>

<button>Quem foi Modificado?</button>

  • Cool, that’s right, but in a more elegant way! + 1

  • And now hehe how do I include this in the other question you answered? -) Like, some fields from that other question are with display=none, So when you change a select for example, you open a field that’s not accounted for... although I don’t know, in your other question code that’s already solved? Because for example, it can have 10 fields, but only 8 visible, and if you do not choose a certain option, these two will not open. In this case the bar will not finish completing before? I could understand?

  • If the element is only hidden with CSS, it exists in the document and will be counted. It would not count if the inputs were created dynamically

2

Well, basically what I understand is that you want to capture the changes of each element of the class ocultosOuOpcionais and then add them up:

Capturing the difference in characters

As explained in that question the best way to calculate the difference between two strings is using the algorithm of Distance from Levenshtein:

function levenshtein(str1, str2) {
  var m = str1.length,
      n = str2.length,
      d = [],
      i, j;

  if (!m) return n;
  if (!n) return m;

  for (i = 0; i <= m; i++) d[i] = [i];
  for (j = 0; j <= n; j++) d[0][j] = j;

  for (j = 1; j <= n; j++) {
    for (i = 1; i <= m; i++) {
      if (str1[i-1] == str2[j-1]) d[i][j] = d[i-1][j-1];
      else d[i][j] = Math.min(d[i-1][j], d[i][j-1], d[i-1][j-1])+1;
    }
  }
  return d[m][n];
}

In my example the function is named captureChanges().

To capture this difference from the initial and current value of a input, use the .defaultValue and the .value, respectively. I adapted to your code in the following way:

var ocultosOuOpcionais = [].slice.call(document.querySelectorAll(".ocultosOuOpcionais"));
var mudados = [];
var mudancas = [];
var ocultosOuOpcionaisMudados = 0; 

ocultosOuOpcionais.forEach(function (input, indice) {
  input.addEventListener("input", function (event) {
    if (event.target.defaultValue == event.target.value) {
      mudados[event.target.id] = 0;
    } else {
      mudados[event.target.id] = event.target.defaultValue;
    }
    mudancas[indice] = captureChanges(mudados[event.target.id], event.target.value);
  });

The above code is an adaptation to the Tobymosque Jsfiddle present in the question comments.

Done this, just add up the differences of each input:

input.addEventListener('keyup', function(){
  mudancas.forEach(function(el, index){
    ocultosOuOpcionaisMudados += parseFloat(el);
  })
  ocultosOuOpcionaisMudados = 0; // É importante que ao final se zere o valor para que não se acumule exacerbadamente
})

Putting all the code together

function captureChanges(str1, str2) {
  var m = str1.length,
    n = str2.length,
    d = [],
    i, j;

  if (!m) return n;
  if (!n) return m;

  for (i = 0; i <= m; i++) d[i] = [i];
  for (j = 0; j <= n; j++) d[0][j] = j;

  for (j = 1; j <= n; j++) {
    for (i = 1; i <= m; i++) {
      if (str1[i - 1] == str2[j - 1]) d[i][j] = d[i - 1][j - 1];
      else d[i][j] = Math.min(d[i - 1][j], d[i][j - 1], d[i - 1][j - 1]) + 1;
    }
  }
  return d[m][n];
}

var ocultosOuOpcionais = [].slice.call(document.querySelectorAll(".ocultosOuOpcionais"));
var mudados = [];
var mudancas = [];
var n = 0;
var ocultosOuOpcionaisMudados = 0;

ocultosOuOpcionais.forEach(function(input, indice) {
  input.addEventListener("input", function(event) {
    if (event.target.defaultValue == event.target.value) {
      mudados[event.target.id] = 0;
    } else {
      mudados[event.target.id] = event.target.defaultValue;
    }
    mudancas[indice] = captureChanges(mudados[event.target.id], event.target.value);
  });
  input.addEventListener('keyup', function() {
    mudancas.forEach(function(el, index) {
      n += parseFloat(el);
    })
    ocultosOuOpcionaisMudados = n;
    n = 0;

    document.getElementsByTagName("h4")[0].innerHTML = "Mudanças no total:";
    document.getElementsByTagName("p")[0].innerHTML = ocultosOuOpcionaisMudados;
  })
});
<input type="text" class="ocultosOuOpcionais">
<br>
<input type="text" class="ocultosOuOpcionais">
<br>
<input type="text" class="ocultosOuOpcionais">
<br>
<input type="text" class="ocultosOuOpcionais">
<br>
<h4></h4>
<p></p>

  • 1

    Another excellent answer! Sopt is too much or it’s not!? :-)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.