If inside the Loop does not work properly

Asked

Viewed 49 times

0

Good evening. I have the following function:

function verificaOnOff(){

  for(var i in tbModulos){

    var mod = tbModulos[i];

    $.get('http://'+ mod.ip +'/rele', function(data) {
        if (data == '1') {
          $('#icone-'+i).removeClass('branco');
          $('#icone-'+i).addClass('amarelo');
          $('input[id="'+i+'"]').prop('checked', true);
        } else {
          $('#icone-'+i).removeClass('amarelo');
          $('#icone-'+i).addClass('branco');
          $('input[id="'+i+'"]').prop('checked', false);
        }
    })
  }
}

It, when called, checks whether a relay is on or not, via GET (0 or 1). If you receive 1, you change some CSS parameters, and vice versa.

The problem is, it’s only changing the last one. Where I’m going wrong?

  • 1

    Put a console.log(i, data) within the $.get to see if it is returning and what is the return

  • @Andersoncarloswoss: 1 1, repeated 2 times. The two relays are connected.

  • 1

    You’re doing a get in a loop for.. only the last one will return because it’s totally asynchronous.

1 answer

3


This possibly happened because the reference of i will be the same for all requests. As these are asynchronous requests, the loop will end quickly, reaching the maximum value of i, which in this case must be 1, before the requisitions are completed; thus, when they are completed, the function callback will be called, all with the value of i equal to 1. To circumvent this, you will need to create separate references to the value of i for each request. The easiest way to do this is to import it into a unique scope of each request, within a function:

function rele(modulo, i) {
    return $.get('http://'+ modulo.ip +'/rele', function(data) {
        const icone = $('#icone-'+i)
        const isOn = (data == '1')

        icone.removeClass(isOn ? 'branco' : 'amarelo');
        icone.addClass(isOn ? 'amarelo' : 'branco')
        $('input[id="'+i+'"]').prop('checked', isOn);
    })
}

function verificaOnOff(modulos){
    $.each(modulos, (i, modulo) => rele(modulo, i));
}

Thus the value of i of each request will be limited by the scope of the function rele, unique to each one. Also, some other improvements have been made to the code.


Instead of adding and removing classes, why not use a data-attribute? With CSS itself you can customize the elements according to the attribute value. See an example:

$('[data-status]').on('click', function (event) {
  const newStatus = ($(this).attr('data-status') == '0') ? '1' : '0'
  $(this).attr('data-status', newStatus)
});
li {
  cursor: pointer;
}

li[data-status='0'] {
  color: lightgray;
}

li[data-status='1'] {
  color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<ul>
  <li data-status='0'>Item 1</li>
  <li data-status='0'>Item 2</li>
  <li data-status='0'>Item 3</li>
  <li data-status='0'>Item 4</li>
  <li data-status='0'>Item 5</li>
</ul>

So your code would look something like:

function rele(modulo, i) {
    return $.get('http://'+ modulo.ip +'/rele', function(data) {
        $('#icone-'+i).attr('data-status', data)
        $('input[id="'+i+'"]').prop('checked', data == '1');
    })
}

What simplifies a little.

  • It worked perfectly. Thank you very much for the help and explanation!

  • Hmm, got it. I didn’t know that, I’ll use it. Thanks again Anderson!

Browser other questions tagged

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