Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery AJAX and handling different dataTypes

I'm using ASP.Net MVC, but this applies to any framework.

I'm making an Ajax call to my server, which most of the time returns plain old HTML, however if there is an error, I'd like it to return a JSON object with a status message (and a few other things). There doesn't appear to be a way for the dataType option in the jQuery call to handle this well. By default it seems to parse everything as html, leading to a <div> being populated with "{ status: 'error', message: 'something bad happened'}".

[Edit] Ignoring the dataType object and letting jQuery figure out doesn't work either. It views the type of the result as a string and treats it as HTML.

One solution I came up with is to attempt to parse the result object as JSON. If that works we know it's a JSON object. If it throws an exception, it's HTML:

$.ajax({
    data: {},
    success: function(data, textStatus) {
        try {
            var errorObj = JSON.parse(data);
            handleError(errorObj);
        } catch(ex) {
            $('#results').html(data);
        }
    },
    dataType: 'html', // sometimes it is 'json' :-/
    url: '/home/AjaxTest',
    type: 'POST'
});

However, using an Exception in that way strikes me as pretty bad design (and unintuitive to say the least). Is there a better way? I thought of wrapping the entire response in a JSON object, but in this circumstance, I don't think that's an option.

Here's the solution that I got from Steve Willcock:

// ASP.NET MVC Action:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AjaxTest(int magic) {
    try {
        var someVal = GetValue();
        return PartialView("DataPage", someVal);
    } catch (Exception ex) {
        this.HttpContext.Response.StatusCode = 500;
        return Json(new { status = "Error", message = ex.Message });
    }
}




// jQuery call:

$.ajax({
    data: {},
    success: function(data, textStatus) {
        $('#results').html(data);
    },
    error: function() {
        var errorObj = JSON.parse(XMLHttpRequest.responseText);
        handleError(errorObj);
    },
    dataType: 'html',
    url: '/home/AjaxTest',
    type: 'POST'
});
like image 701
swilliams Avatar asked May 11 '09 21:05

swilliams


3 Answers

For your JSON errors you could return a 500 status code from the server rather than a 200. Then the jquery client code can use the error: handler on the $.ajax function for error handling. On a 500 response you can parse the JSON error object from the responseText, on a 200 response you can just bung your HTML in a div as normal.

like image 193
Steve Willcock Avatar answered Oct 01 '22 17:10

Steve Willcock


While Steve's idea is a good one, I'm adding this in for completeness.

It appears that if you specify a dataType of json but return HTML, jQuery handles it fine.

I tested this theory with the following code:

if($_GET['type'] == 'json') {
    header('Content-type: application/json');
    print '{"test":"hi"}';
    exit;
} else {
    header('Content-type: text/html');
    print '<html><body><b>Test</b></body></html>';
    exit;
}

The $_GET['type'] is just so I can control what to return while testing. In your situation you'd return one or the other depending on whether things went right or wrong. Past that, with this jQuery code:

$.ajax({
    url: 'php.php?type=html', // return HTML in this test
    dataType: 'json',
    success: function(d) {
        console.log(typeof d); // 'xml'
    }
});

Even though we specified JSON as the dataType, jQuery (1.3.2) figures out that its not that.

$.ajax({
    url: 'php.php?type=json',
    dataType: 'json',
    success: function(d) {
        console.log(typeof d); // 'object'
    }
});

So you could take advantage of this (as far as I know) undocumented behavior to do what you want.

like image 36
Paolo Bergantino Avatar answered Oct 01 '22 17:10

Paolo Bergantino


But why not return only JSON regardless of the status (success or error) on the POST and the use a GET to display the results?
It seems like a better approach if you ask me.

like image 32
andi Avatar answered Oct 01 '22 18:10

andi