Search code examples
javascriptphpxmlxmlhttprequest

XMLHTTPRequest keeps looping through conditional statements?


I am trying to run a conditional statement based on the readystate of my xhr. The readystate switches to 1 after open() is called (line 2), but never changes after that. It skips over the conditionals, and nothing is sent.

I'd love to know why readystate is not changing?

  var xhr = new XMLHttpRequest();
  xhr.open('POST', submitUrl, true);
  xhr.setRequestHeader('Content-Type', 'application/json');
  xhr.onreadystatechange = function () {
    if (xhr.readyState === 4) {
      function1();
      function2();
    } else if (xhr.status === 400) {
      function3();
      function2();
    } else if (xhr.status != 400 && xhr.status != 200) {
        function5();
        function6();
    }
  }
  xhr.send(body);
})

Solution

  • According to your code, your observations, and the context you've provided in the comments, you've two issues:

    • sending form data
    • evaluate the response

    Let's assume some basic form like this:

    <form action="endpoint.php" method="post">
        <input type="hidden" name="token"  value="value">
        <input type="submit" name="submit" value="submit">
    </form>
    

    To be able to send this form's data ourselves, we need to make sure we're intercepting the browser's default behaviour of submitting it right away as soon as the submit button is clicked (cf. also epascarello's comments):

    // Intercept the onsubmit event
    document.querySelector('form').onsubmit = function (evt) {
    
        // Make sure to prevent the form from being submitted by
        // the browser, which is the default behaviour. 
        evt.preventDefault();
    
        // Get the form's data
        let form = new FormData(evt.target);
    
        // We're going to explicitly submitting our data
        // as JSON, so make sure it actually is JSON.
        let data = JSON.stringify(Object.fromEntries(form)); // https://stackoverflow.com/a/55874235/3323348
    
        sendRequest(data); // Our submit function, which we'll define next (see below)
    };
    

    Now, we'd be able to actually send the data, and to properly handle messages and status codes send back by the server. But first, let's have a quick look at your if clauses, because they might not work the way you expect them to. Especially because state and status aren't mutually exclusive - a readyState of 4 doesn't mean the server hasn't answered with an HTTP status code denoting an error (like a 404):

    if (xhr.readyState === 4) {
      
        console.log(xhr.status); // Could be any HTTP status code 
    
    } else if (xhr.status === 400) {
      
        console.log(xhr.readyState); // Could be any readyState besides 4
    
    } else if (xhr.status != 400 && xhr.status != 200) {
        
        console.log(xhr.readyState); // Could be any readyState besides 4...
        console.log(xhr.status);     // ...and any HTTP status code besides a Bad Request (400) and an OK (200)
    }
    

    So let's tackle that part a bit different, while the rest of your code stays the same (though wrapped in a function):

    function sendRequest(data) {
    
        const xhr = new XMLHttpRequest(); 
    
        xhr.open('POST', '/endpoint.php'); // All requests are asynchronous by default, 
                                           // so we can drop the third parameter.
        xhr.setRequestHeader('Content-Type', 'application/json');
    
        // Since we've just created a client and initialized
        // a request, we'll receive notifications for states
        // 2-4 only (instead of 0-4).  
        xhr.onreadystatechange = function () {
            
            console.log(xhr.readyState); // Let's watch the readyState changing
    
            // We're interested in the final result of our request only (state 4),
            // so let's jump all other states.  
            if (xhr.readyState !== 4) {
    
                return;
            }
    
            const status = xhr.status; // HTTP status code
            const type   = status.toString().charAt(0); // Get class of HTTP status code (4xx, 5xx, ...)
    
            if ([4,5].includes(type)) {
    
                console.log('An error occured', status, xhr.responseText);
                return;
            }
    
            if (status == 200) {
    
                console.log('OK', xhr.responseText);
                return;
            }
    
            // Server answered with a status code of 1xx, 3xx, or > 200.
            console.log('Unexpected response', status, xhr.responseText);
        }
    
        xhr.send(data);
    }
    

    Now, you should be able to successfully send form data (and send it as JSON) and evaluate the HTTP response status codes. Instead of using XMLHttpRequest, though, you might want to consider fetch() instead.

    Misc: