0

In the function below, I have this 2 variables, size and total, which should be acessible in the entire function block, but when the execution arrives in the third if, they present the value undefined:

function update_cart() {
  var cart_size = document.getElementById('cart_size');
  var cart_status = document.getElementById('cart_status');
  var cart_total = document.getElementById('cart_total');

  var size, total;

  if(cart_size !== null) {
    var cliente = cart_size.dataset.cliente;
    var url = cart_size.dataset.url;

    var xhr = new XMLHttpRequest();
    xhr.open("POST", url, true);
    xhr.onreadystatechange = function() {
      if (xhr.readyState == 4 && xhr.status == 200) {
        size = xhr.responseText;
        cart_size.innerHTML = size;
        if(size == 0)
          cart_size.style.display = 'none';
        else
          cart_size.style.display = 'block';
      }
    };
    var formData = new FormData();
    formData.append("cliente", cliente);
    xhr.send(formData);
  }

  if(cart_total !== null) {
    var cliente = cart_total.dataset.cliente;
    var url = cart_total.dataset.url;

    var xhr = new XMLHttpRequest();
    xhr.open("POST", url, true);
    xhr.onreadystatechange = function() {
      if (xhr.readyState == 4 && xhr.status == 200) {
        total = xhr.responseText;
        var currency = new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(total);
        cart_total.innerHTML = currency;
      }
    };
    var formData = new FormData();
    formData.append("cliente", cliente);
    xhr.send(formData);
  }

  if(cart_status !== null) {
    switch(size) {
      case 0:
        cart_status.innerHTML = 'A cesta de compras está vazia.';
        document.getElementById('table').style.display = 'none';
        break;
      case 1:
        cart_status.innerHTML = size + ' produto adicionado na cesta, com valor ' + total;
        document.getElementById('table').style.display = 'block';
        break;
      default:
        cart_status.innerHTML = size + ' produtos adicionados na cesta, com valor ' + total;
        document.getElementById('table').style.display = 'block';
        break;
    }
  }
}

I already tried declare them with var and let, with the same result. In the page where cart_status exists, both cart_size and cart_total exists.

Anyone can give a hint of how fix that issue?

Kleber Mota
  • 8,521
  • 31
  • 94
  • 188

3 Answers3

0

You have to understand that the call to xhr.onreadystatechange is an asyncrnous call. So, if you are trying to capture/user the value of size or total before the async action has happend/resolved, you will get the undefined value in them.

What you have to do there is use callbacks to deal with them values, after they come from the asyncrnous call.

MarkSkayff
  • 1,334
  • 9
  • 14
0

It doesn't work because these variables are defined in a callback.

xhr.onreadystatechange = function() {
      if (xhr.readyState == 4 && xhr.status == 200) {
        size = xhr.responseText;
        cart_size.innerHTML = size;
        if(size == 0)
          cart_size.style.display = 'none';
        else
          cart_size.style.display = 'block';
      }
    };

This code is called asynchronously, read: later, when you receive the response of the network call.
If you want to access the variable, you must move the code that uses the variable to the callback.

html_programmer
  • 18,126
  • 18
  • 85
  • 158
0

As others said, XMLHttpRequest is asyncronious by default. Meaning that it won't stop the rest of the script from executing.

So you could wait until the first request finished to do the next one, and after the second request finished, you should have all the values you need.

Something like this I think:

var firstRequest = new XMLHttpRequest();
firstRequest.open('POST', 'someUrl');
firstRequest.onreadystatechange = function() {
  if (firstRequest.readyState == 4 && firstRequest.status == 200) {
    size = firstRequest.responseText;
    var secondRequest = new XMLHttpRequest();
    secondRequest.open('POST', 'someOtherUrl');
    secondRequest.onreadystatechange = function() {
      if (secondRequest.readyState == 4 && secondRequest.status == 200) {
        total = secondRequest.responseText;
        // Now you should have both size and total variables available
      }
    };
  }
};

Not pretty but it should work.

Camilo
  • 6,504
  • 4
  • 39
  • 60