3

I would like to display an error message if my Ajax call is unsuccessful. Simple enough but I cannot modify the Ajax function. I created an onClick listener that does a few things when my AJAX call is successful. I would just like to do something when the call is unsuccessful.

So If I decide to add:

 if (xhr.status !== 200) {
   //Error Message here
   }

Where would it be placed?

JSFiddle Example Here

My html is:

<div id="test-form">
      <h2>Add a User:</h2>
      <label for="Username:">
       <input id="username" type="text" name="username" placeholder="Type username here">
     </label>

      <label for="Email:">
      <span id='result'></span>
      <input id="email" type="email" name="email" placeholder="email">
      </label>
      <button id="myButton">add user</button>
      <h2 class="clear">Users:</h2>
      <ul id="users"></ul>
    </div>

My code is:

 var el = document.getElementById("myButton");
    el.onclick = function() {
      addUser(username, email, onSuccess);
    }

    function onSuccess(result){
      var filter = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;

      var username = document.getElementById("username").value;
      var email = document.getElementById("email");
        var message = document.getElementById("result").classList;

      document.getElementById("users").innerHTML+= '<li>' + username +'</li>';

    if (!filter.test(email.value)) {
        document.getElementById('result').innerHTML+='Not a valid email';
        email.focus;
         return false;
     } else {


        message.add("hide");
      }

    }



    // Do not modify this function. Add user service wrapper.
    function addUser(username, email, callback) {
        var xhr = new XMLHttpRequest();
        var response;
        var success = (!!Math.round(Math.random()));

        if (!success){
            response = JSON.stringify({
                success: success,
                error: "Oups, something went wrong!"
            });
        } else {
            response = JSON.stringify({
                success: success,
                user: {
                    username: username,
                    email: email
                }
            });   
        }

        xhr.open("POST", "/echo/json/");
        xhr.onload = function () {
                if (xhr.status === 200) {
                    callback(JSON.parse(xhr.responseText));
            }
        }
        xhr.send("json=" + response);
    };
Mariton
  • 601
  • 2
  • 12
  • 28
  • 1
    so you aren't allowed to modify the "addUser" function? In that case you're a bit stuck because it hasn't bothered to handle error conditions. You need to modify the xhr.onload callback to actually do something when there's an error (i.e. non-200 response). – ADyson Jul 07 '17 at 13:11
  • Does you responseText contain error information? or do you just want to test for issues with the server response codes? if the former like ADyson states you need to check for more than just 200 status code. Otherwise if you get an empty result from your ajax query you would simply look for that in your javaScript function – Claus Jul 07 '17 at 13:14
  • `if (xhr.status === 200)` <-- This is where it checks for a successful response. To check for other response codes, you'd add other conditions. Or if an "error" from this resource is in the form of messages in the response body itself (not using proper response codes), then you could check for that in the `onSuccess` function by examining the `result` variable. – David Jul 07 '17 at 13:16
  • @ ADyson No I'm not allowed to modify the addUser function – Mariton Jul 07 '17 at 13:32
  • use new API `fetch(...).then(success).catch(error); – zb' Jul 07 '17 at 13:46
  • Do not only rely on error response, I would suggest you to add some more methods in error response there might be some circumstances when you would require them to debug your code. – sagar Jul 07 '17 at 13:49
  • @zb' Do you have an example? – Mariton Jul 07 '17 at 13:55
  • @Mariton - read about [fetch here](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API#Concepts_and_usage) and see an example [here](https://developer.mozilla.org/en-US/docs/Web/API/Response#Examples). Would this happen to be homework? If so, [see this meta post about it](https://meta.stackoverflow.com/a/334823/1575353) – Sᴀᴍ Onᴇᴌᴀ Jul 07 '17 at 13:58
  • @ Sam Onela No this isn't homework. I'm just trying to figure something out – Mariton Jul 07 '17 at 14:07
  • 1
    why aren't you allowed to modify this function, if that would be the simplest solution? You won't break other code that relies on it if all you do is add some extra functionality for error handling. – ADyson Jul 07 '17 at 14:09
  • @Mariton: "I want my code to do something different, but without modifying it" is kind of a non-starter. *Why* can't you modify the code? Perhaps *that* is the problem that truly needs to be solved first. – David Jul 07 '17 at 14:11
  • @David That's not what I'm asking at all. If you look at my code there are certain parts that I can modify but for this example I cannot modify the Ajax call but I can add a listener to the Ajax call. Look at it this way. If I am receiving the code from somewhere else and or the code is generic and has one function there should be other ways to watch the function. What I'm asking is from a normal real world situation. – Mariton Jul 07 '17 at 14:17
  • 1
    @Mariton you basically can't assign a listener to the ajax call from code outside the addUser() function because due to variable scoping you haven't got access to the XHR object which is within that function and is not exposed by it. Someone commented on one of the answers below regarding the solution here: https://stackoverflow.com/questions/5202296/add-a-hook-to-all-ajax-requests-on-a-page which is a possible workaround involving messing with the XHR prototype object. That's probably about as good as it gets. – ADyson Jul 07 '17 at 14:20
  • @SamOnela that assumes that the actual response coming from the server contains error information in the response, despite having returned an "OK" response. Big assumption, and doesn't help if that's not the case. If we can't modify the JS which fetches the data from the server, realistically we have to assume we can't modify the response from the server either, otherwise it makes the whole exercise a bit meaningless. – ADyson Jul 07 '17 at 14:31
  • 1
    @SamOnela And also if you read the question, OP is asking where to put some code that checks if the status is _not_ 200, which implies that your suggestion would not be particularly useful. The issue is that OP is saying that this code cannot be put inside the addUser function, which is the only place in the code where the `xhr` object would actually be in scope and accessible like this. In other words, asking the impossible. – ADyson Jul 07 '17 at 14:33
  • @ADyson yeah it seems impossible – Sᴀᴍ Onᴇᴌᴀ Jul 07 '17 at 14:36
  • 1
    @Mariton: After looking around, it seems that the link being posted in other comments (https://stackoverflow.com/questions/5202296/add-a-hook-to-all-ajax-requests-on-a-page) might be your last best hope here. Modifying the XHR object that JavaScript is using itself seems a bit risky, but architecturally the concept is at least sound. Since you can't modify the code, you'd need to modify the dependencies being used by the code. – David Jul 07 '17 at 14:37
  • @ David Thanks David – Mariton Jul 08 '17 at 17:30

3 Answers3

1

Without modifying the function addUser(), the seemingly only possible way to do this would be modifying the XMLHttpRequest prototype, as suggested by this answer, to add an event listener for the readystatechange event (using addEventListener()). Also, the onerror function could be overridden to detect when an error causes an XMLHttpRequest transaction to fail.

Bear in mind that would affect ALL XMLHttpRequests on the page!

var lastResponseCode, oldSendFunction;
// store the native send()
oldSendFunction = XMLHttpRequest.prototype.send;
// override the native send()
XMLHttpRequest.prototype.send = function() {
    //subscribe to ready state change events
    this.addEventListener("readystatechange", function(readyEvent) {
        //store the response code, to be checked later
        lastResponseCode = readyEvent.target.status;
    });
    // call the native send()
    oldSendFunction.apply(this, arguments);
}
function onSuccess(result) {
    if (lastResponseCode == 200) {
        //last request was successful
        //...
    }
    else {
         //other response was received - could have been 2xx,3xx,4xx,5xx
    }
}

This is saved in this updated plunker but it seems unlikely that will yield a response code other than 200. To test with failing XHR requests, try this PHPfiddle, where every other XHR request will yield a response code of 500.

Sᴀᴍ Onᴇᴌᴀ
  • 8,218
  • 8
  • 36
  • 58
  • This is good but remember I can't modify my addUser function. Take a look at my Fiddle https://jsfiddle.net/jimmyt1001/yw26ncba/27/ – Mariton Jul 07 '17 at 13:49
0

You can check xhr status and when it's not 200 then it was not succeed, Then You can Throw responseText.

if (xhr.status !== 200)
    throw(xhr.responseText);
cнŝdk
  • 31,391
  • 7
  • 56
  • 78
0

I guess this question is asking you to display an error message if the AJAX request return an error and you are not allowed to modify the addUser(). If you pay attention to see the addUser() function

addUser(username, email, callback)

inside this function, the code shows that they are mimicking a random failure situation as follows:

    var success = (!!Math.round(Math.random()));
    if (!success){
        response = JSON.stringify({
            success: success,
            error: "Oups, something went wrong!"
        });
    } else {
        response = JSON.stringify({
            success: success,
            user: {
                username: username,
                email: email
            }
        });   
    }

so I think you can just check the response from callback function. The response will randomly show error or success. So, you don't need to modify addUser() at all.

function onSuccess(result){
      //check your console to see what is the result first, so you can know how it works
      console.log(result);

      if(result.success){
       // do something
       }else{
       // display error message
   }
}