AJAX Javascript Pure Asynchronous

Asked

Viewed 946 times

6

I am trying to recover a data coming from Ajax to use in another function, but I am not succeeding. In jQuery I do this using a parameter called async: false.

But in pure JS I am not able to do. The parameter is false in function .open.

JS

function initMap() {
    var idDealer = document.getElementById('id-concessionaria').value;
    urlBase      = document.getElementsByTagName('body')[0].getAttribute('data-base');

    // Ajax Procura na Base de Dados Latitude e Longitude da Concessionária

    var request  = new XMLHttpRequest();
    request.open('POST', urlBase + '/avaliar-concessionaria/lat-lng', false);
    request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    request.send("id="+idDealer);

    request.onload = function() {
        if (request.status >= 200 && request.status < 400) {
            var data = JSON.parse(request.responseText);
            var lat  = data[0];
            var lng  = data[1];
        }
    };

    // Quero usar as variáveis aqui

    var myLatLng = { lat: lat, lng: lng }
    map = new google.maps.Map(document.getElementById('mapa'), {
        center: myLatLng,
        zoom: 10
    });

    var marker = new google.maps.Marker({
        position: myLatLng,
        map: map,
        title: 'Aqui!'
    });
}
  • 4

    8am, the guy arrives already putting question on Stack. Not arrived right... called the PC sent the question.

  • I edited the reply @Zoom I hope you understand that my other comment was trying to guide you, I never give an orientation just for mimimi or because I cry a lot, it was with the sole intention of helping you ;) Please always assume good intention, I hope you can understand the asynchronous example, because as I said sync will be "discontinued".

2 answers

4


you must use the event readystatechange and not the load.

In any case, I think it is unnecessary to use the header application/x-www-form-urlencoded, the default multipart/form-data is even better.

possible values for the readyState sane:

  • 0 - Not Shipped
  • 1 - Open method executed.
  • 2 - Send method has been called and Headers are already available.
  • 3 - Loading, the [responseText] property already has partial data.
  • 4 - Operation Concluded.

Then we must wait for the readyState == 4 so that we can work on the return of the request.

var idDealer = document.getElementById('id-concessionaria').value;
urlBase      = document.body.dataset.base;

var request  = new XMLHttpRequest();
//terceiro parametro [async] é por default true.
request.open('POST', urlBase + '/avaliar-concessionaria/lat-lng'); 

//não acho necessario, prefiro o "multipart/form-data";
//request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 

request.responseType = "json"; //formato esperado para o retorno.
request.addEventListener("readystatechange", function() {
    if (request.readyState == 4) {
        //normalmente uso apenas o status 200 para verificar se é sucesso.
        if (request.status >= 200 && request.status < 400) { 
            //devido ao request.responseType = "json" não é preciso deserializar o responseText.
            //var data = JSON.parse(request.responseText); 
            var lat  = request.response[0];
            var lng  = request.response[1];

            var myLatLng = { lat: lat, lng: lng }
            map = new google.maps.Map(document.getElementById('mapa'), {
                center: myLatLng,
                zoom: 10
            });

            var marker = new google.maps.Marker({
                position: myLatLng,
                map: map,
                title: 'Aqui!'
            });
        }       
    }   
});

//montando os dados a serem enviados.
//opcionalmente o FormData pode receber como parametro um form, 
//desta forma ele já será preenchido com os dados do form automaticamente.
//caso contrario, use o append para incluir os valores a serem enviados.
var formData = new FormData();
formData.append("id", idDealer);
request.send(formData);

to do synchronously, you don’t need any event, just run the code in a linear way, but in doing so, you will be blocking the thread, so it is not advisable.

var idDealer = document.getElementById('id-concessionaria').value;
urlBase      = document.body.dataset.base;

var request  = new XMLHttpRequest();
request.open('POST', urlBase + '/avaliar-concessionaria/lat-lng', false); 

//não acho necessario, prefiro o "multipart/form-data";
//request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 

request.responseType = "json"; //formato esperado para o retorno.

//montando os dados a serem enviados.
//opcionalmente o FormData pode receber como parametro um form, 
//desta forma ele já será preenchido com os dados do form automaticamente.
//caso contrario, use o append para incluir os valores a serem enviados.
var formData = new FormData();
formData.append("id", idDealer);
request.send(formData);

//normalmente uso apenas o status 200 para verificar se é sucesso.
if (request.status >= 200 && request.status < 400) { 
    //devido ao request.responseType = "json" não é preciso deserializar o responseText.
    //var data = JSON.parse(request.responseText); 
    var lat  = request.response[0];
    var lng  = request.response[1];

    var myLatLng = { lat: lat, lng: lng }
    map = new google.maps.Map(document.getElementById('mapa'), {
        center: myLatLng,
        zoom: 10
    });

    var marker = new google.maps.Marker({
        position: myLatLng,
        map: map,
        title: 'Aqui!'
    });
}
  • The answer would be more interesting with an explanation of what readyState and what it means to have the value 4.

  • I was modifying the function to readystatechange before you send the reply. Now that I will see your solution... as to the status of the request, for me need not explain anything...

  • @Pablo, I’ll add this information.

  • @Zoom, now I noticed that you wanted to do so so so, although I disagree that it is done this way, I will add the answer.

  • Yes, I need the request value to use in the Google Maps map function. But you can recommend another solution...

  • What would be the advised way ? You commented in the code that advises against such a method...

  • @Zoom, in the answer I put two examples, an asincrono (first) and another sincrono (second)... the synchronous form should be avoided.

  • So you advise against both ways ? In the above comment you advise against synchronous and two comments above asynchronous.

  • 1

    @Zoom, errata: I’m sorry for the confusion, in the above comment I wanted to refer to forma sincrona, but I wrote forma asincrona... to forma sincrona which is not advisable, to forma asincrona is encouraged.

  • Got it. Thank you, it worked. And I did it by the asynchronous way, which I imagined to be the right one anyway, so I use it in jQuery.

Show 5 more comments

3

I know you’ve had your answer, but I’d like to explain how to use the XmlHttpRequest API.

When you define false in the third parameter of .open you are defining as synchronous:

open('POST', url, false);

Even if you use .onload or .onreadystatechange they will not work, understand that Ajax is not the technology but the way we use the XmlHttpRequest API, that is only ajax if it is asynchronous, otherwise it is SJAX (Xmlhttprequest synchronous).

See the differences:

Synchronous (this is not Ajax):

var oReq = new XMLHttpRequest();

//Defina como false
oReq.open("GET", "/url", false);

//Espera completar a requisição, geralmente congela o browser
oReq.send(null);

alert(oReq.responseText);

Note that the synchronous "freezes" the webbrowser while the request does not end

Asynchronous (this is Ajax):

var oReq = new XMLHttpRequest();

//Defina como true
oReq.open("GET", "/url", true);

//Função assíncrona que aguarda a resposta
oReq.onreadystatechange = function()
{
    if (oReq.readyState === 4) {
        alert(oReq.responseText);
    }
};

//Envia a requisição, mas a resposta fica sendo aguardada em Background
oReq.send(null);

Note that the asynchronous does not freeze the browser, because in fact the process is in Background and the signal is sent via callback pro .onreadystatechange for each stage of the .readyState

It’s as I explained in this question: Ajax is not a programming language. So what is?

application/x-www-form-urlencoded vs multipart/form-data

I understand what Tobymosque said and I don’t disagree, just that we need to understand the differences, look at the setRequestHeader('Content-Type', ...); it’s not just something from XmlHttpRequest as you may already know, it’s an instruction that tells you how data should be interpreted by the back-end.

Use new FormData works perfectly as explained, but if we don’t have browser support for this class then we have to use application/x-www-form-urlencoded.

The setRequestHeader('Content-Type', ...); is equivalent to the attribute enctype in the <form>, with them we define how the form data will be encoded when sending them to the server, there are 3 types of values for this attribute:

  • application/x-www-form-urlencoded this is the default value in <form>, but not in the XmlHttpRequest. In it all characters are encoded before being sent, for example spaces are exchanged for + and special characters are converted to ASCII HEX values.

  • multipart/form-data It does not encode the data, you must use this value when doing uploads.

  • text/plain spaces are converted into signs of + but other characters will not be encoded.

Assuming the browser is a little older and not supported FormData then you’ll have to use application/x-www-form-urlencoded and codify the past in .send(...);, thus:

var oReq = new XMLHttpRequest();

//Defina como true
oReq.open("POST", "/url", true);
oReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

//Função assíncrona que aguarda a resposta
oReq.onreadystatechange = function()
{
    if (oReq.readyState === 4) {
        alert(oReq.responseText);
    }
};

oReq.send('nome=' + escape('João de Nobrega'));

Or:

oReq.send('nome=' + encodeURIComponent('João de Nobrega'));

If send without the application/x-www-form-urlencoded they will go with the format RAW and if you don’t use encodeURIComponent or escape it is likely that he does not recognize what comes after João

Some details here: Upload does not work $_FILES Undefined index error

Completion

Do not use synchronous because it is in disuse and browsers are issuing warnings and in the future will remove synchronous so do not use the false, use true or omit the third parameter (by default .open uses true) thus:

request.open('POST', urlBase + '/avaliar-concessionaria/lat-lng');

How the code should look

As I said synchronous will soon no longer work in modern browsers, for this you need to understand the difference of callback and Return, read this:

Your code should look like this:

function initMap() {
    var idDealer = document.getElementById('id-concessionaria').value;
    urlBase      = document.getElementsByTagName('body')[0].getAttribute('data-base');

    var myLatLng, marker, myLatLng; //Torna as variáveis acessíveis no escopo de `initMap`

    var exec = function(lat, lng) {
        myLatLng = { "lat": lat, "lng": lng }
        map = new google.maps.Map(document.getElementById('mapa'), {
            center: myLatLng,
            zoom: 10
        });

        var marker = new google.maps.Marker({
            position: myLatLng,
            map: map,
            title: 'Aqui!'
        });

        //Resto da função
    };

    var request  = new XMLHttpRequest();
    request.open('POST', urlBase + '/avaliar-concessionaria/lat-lng', true);
    request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

    request.onreadystatechange = function() {
        if (oReq.readyState === 4 && request.status >= 200 && request.status < 400) {
            var data = JSON.parse(request.responseText);
            var lat  = data[0];
            var lng  = data[1];
            exec(lat, lng);
        }
    };
    request.send("id=" + idDealer);
}

This way it will work asynchronously.

Browser other questions tagged

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