Link to home
Start Free TrialLog in
Avatar of elepil
elepil

asked on

How to access a custom field in Exception in jQuery's jqXHR object?

I created a subclass of PHP's Exception class (which I'll call MyException) because I needed to add an additional property that contains a more user-friendly message for the user. So aside from the usual properties of the Exception class (i.e., $message, $code, ...), I added a property called $userMessage. I ran into no problems with this, and it works very well within PHP.

But when I get to the final moment when I throw a MyException within PHP for .ajax()'s .fail() handler to receive, how do I access this custom property (i.e., $userMessage) from the jqXHR object? It wasn't the 'statusText', not the 'responseText' property either.

Thanks.
Avatar of Rob
Rob
Flag of Australia image

You need to catch the exception and return the data from PHP to the browser (jquery and just like you would any other data success or failure).

try {
...
}
catch ($e) {
header('application/json');
echo json_encode($e);
}
In addition, jQuery's .fail() will only be called when there is an HTML error code e.g. 404, 500 so the fact that your PHP fails but the communication between the browser (jQuery) and your server (PHP) is working then jQuery will call .success() when the data is returned.
ASKER CERTIFIED SOLUTION
Avatar of Rob
Rob
Flag of Australia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks Ray, I almost posted your article but thought you'd be asking before too long!
Avatar of elepil
elepil

ASKER

To Rob Jurd.

What you have succinctly and clearly conveyed to me is the same as what I got from the forum at jQuery.com as well -- that I had to use the .success/.done handler to handle both success and failures from the PHP script. I guess the "slight purist" in me thinks that the .success/.done handlers should handle only successful operations, and the .fail() handler should handle only the unsuccessful operations. But I now realize that there is no mechanism in place for PHP to pass a message through the jqXHR object. So yes, I now realize I have to pass my message through the .success handler.

I also got the chance to see and learn how more experienced PHP developers do things, and I greatly appreciate seeing your method. I was using a much simpler method of returning a string "true" for a successful operation, and any other string is an automatic failure where the message should be displayed right away in a <div id="message"></div> at the bottom of the UI. Mine is crude and simple, but your method is better because a JSON object can provide a lot more detail than a simple string. I have also repetitively seen people use json_encode() that I really think I should look into that in greater depth. So I'm happy because I received confirmation that I cannot use the .fail() handler for this, and I got more insight in seeing how you did it. Thank you very much, Rob!


To Ray Paseur,

Ray, you are one of the most helpful people in this forum, 99% of the time, it's a pleasure to interact with you. Even when you don't have a direct solution to an inquiry, you manage to somehow provide supplemental information that provides a little more richness on top of what others have already given, such as what you have done in this case. Much appreciated.
elepil,

I'm glad you've got so much out of this conversation.  

As I was working on another project, I thought of you and this question as it occurred to me that you can control the http status codes that are returned to the browser.  I'm hesitant to suggest this but wanted to give you the option.  The status codes reflect the communication between the client and the server as we've all mentioned above.

In this project I'm working on, I'm using a URL routing system called Slim (http://docs.slimframework.com/response/status/).  It's great to use for a lot of different reasons but the main ones are for SEO (Search Engine Optimization) as the URLs can be prettified e.g. /search/product-id/product-name etc but it also adds a sense of logical organisation to the requests made from your page.  The long and short of it is that when you send a response to the client (using Slim), you can set the http status code along with any relevant information.

So definitely worth a look.
Avatar of elepil

ASKER

Rob,

Thank you for that suggestion. Reading briefly about it, so I'd have to install SLIM, then use their API to put the user-friendly message I want in the header which I can then extract on the JavaScript side. I'll definitely think about it.

Your response to my post did more than just provide me another way of sending data from server to client. You also confirmed to me what I was told in the jQuery forums that it is not possible to send custom data through jQuery's jqXHR object. I got the impression that developers who use jQuery course their data through the .done()/.success() handlers rather than the .fail().

By the way, I noticed you would use header('application/json') prior to echoing your json string to the client. I understand what it's for, i.e., to be very specific to PHP and the receiving end what kind of data you're sending. But when I tried it, it didn't seem to matter if it was there or not. So now I'm curious, did you experience a problem in the past which led you to adhere to this practice?
You don't want to blur the line too much between an error on your application and an error in the browsers communication with the server. One reason is that the browsers (and jQuery) may one day change how those errors are handled and you do not want your application reliant on that. I.e.using the .fail() you're saying to someone else that reads your code, that there was a communication error with the server. So even though it's possible, It's just confusing for anyone else interpreting your code.
I always use the header that that's to the days I'm sending because of the reason I mentioned above where the client (this could be a browser [of which there are quite a few], an app, native software etc) may ignore different types of headers at this point but should they choose to actually do something, you don't want to be caught out.
I know the chrome browser will parse the response as an object automatically if you set the json header.
Just a thought :)
Avatar of elepil

ASKER

Thanks for the sage advice, Rob. :)
Avatar of elepil

ASKER

Rob,

Sorry to bother you again, but I wanted to ask you about your usage of :

header('application/json');

Open in new window


I actually asked you about this in one of my previous posts, but I'm not sure I got an answer from you. For some odd reason, it didn't seem to have an effect on my local server, but when I deployed my application to the remote host, the weirdest thing happened. My PHP side would execute perfectly fine, and it would even successfully execute this final statement:

echo json_encode("<whateverResultStringHere>";

Open in new window


And here's the odd thing -- instead of reaching .ajax()'s .done()/.success() handler, it keeps hitting the .fail() handler! This phenomenon confused the heck out of me at first, and for the lack of anything better, I decided to remove the header() function, then it went through fine.

I asked you before what in your experience could have encouraged you to use header(). I'm curious because although I got past my issue by removing header(), did you ever encounter an issue because you didn't use it? I'm asking this just for my own learning.

Thanks.
Please see my last comment as I mentioned why I use the header: http:#a40732743

So this confirms what I thought to be true.  Check your jQuery.ajax() dataType flag as it should be set to 'json'.
Avatar of elepil

ASKER

Rob,

I did read that comment you made but wasn't sure I understood you.

You said:
the client (this could be a browser [of which there are quite a few], an app, native software etc) may ignore different types of headers at this point but should they choose to actually do something, you don't want to be caught out.

Correct me if I misunderstood, but I interpreted what you said as your wanting to be proactive in the event various clients eventually start doing something with the different header types. But in my mind, what if they change the syntax of "application/json" to "app/json", or something like that. Wouldn't the possibility of header format change possibly work against you as well?

You were also saying that using the header() with Chrome browser would cause it to parse it automatically. But by specifying dataType: "json" in .ajax(), that's what parses it for me. I actually didn't have to do a JSON.parse() on the result that came in.

Did I understand your post correctly before?
be proactive in the event various clients eventually start doing something with the different header types
That's right but it would seem that they are already.

Here's an example to show you what's going on with the header: http://jsbin.com/bunefu/1/edit?js,console

In both ajax examples, the dataType is 'json'.  The difference between the two requests is the first one returns the header 'application/html' and second 'application/javascript' (akin to application/json for all intents and purposes).  The first call fails, the second works.

So in your case, I would set the header to 'application/json' in your PHP, dataType: 'json' in your jQuery and use console.dir(textStatus) to see what the error message is.