2

Somehow I have confused myself.

Somehow I got it in my head that when hitting PHP with AJAX (like $.post), you had to echo back a "true" or "false" instead of returning true/false. I see now that is not the case, but can someone break it down for me?

Is it that there is a problem testing a boolean? Like here

... 
$.post('ajax/doThing',{data: data},
    function(response) {
        if(response) {
            doThis();
        }else{
            doThat();
        }

That is the problem case, correct? Here I cannot return true/false, instead I must echo back a string and test the string, yes?

if(response === "true")

But I have seen boolean true/falses returned to ajax functions. What is the use of this, if you cannot test a boolean on the AJAX side? And why can't ajax test a boolean?

Or am I still confused?

EDIT

Just wanted to thank everyone for their good answers on this. I am now +2 smrter.

K.K. Smith
  • 990
  • 2
  • 9
  • 28

4 Answers4

6

You might also look at returning HTTP error codes rather than returning a "success" response (HTTP status code 200) when the request wasn't really successful, and then use an error callback to handle unsuccessful requests.

But if you want to keep using status code 200 (and a lot of people do that):

The data transferred between the client and the server is always text. The trick is to make sure that the client and server agree on how the client should deserialize the text (transform it upon receipt). Typically you might return one of four things:

  1. HTML (if it's going to populate page elements)

  2. JSON (if you want a lightweight, fast way to send data to the client)

  3. XML (if you want a heavier-weight, fast way to send data to the client)

  4. Plain text (for whatever you want, really)

What the client does will depend on what Content-Type header you use in your PHP page.

My guess is that you're using any of several content types that end up passing on the data as a string to your callback. The string "true" is truthy, but so is the string "false" (only blank strings are falsey).

Long story short: I'd probably use this in my PHP:

header('Content-Type', 'application/json');

...and the return this text from it:

{"success": true}

or

{"success": false}

...and then in your success handler:

if (response.success) {
    // It was true
}
else {
    // It was false
}

Alternately, you can return a Content-Type of text/plain and use

if (response === "true") {
    // It was true
}
else {
    // It was false
}

...but that's kind of hand-deserializing where you could get the infrastructure to do it for you.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • I see a lot about sending headers, and I have managed to do quite a few ajax functions without ever having worried about sending headers. Generally I would echo back a simple string, or json_encode an array or object. Have I just been "lucky" that everything seems to have worked? Or maybe because my functions have been fairly basic. I know that $.ajax "guesses" at the response type if you don't specify it.. so is that what has saved me? – K.K. Smith Feb 05 '13 at 13:22
  • 1
    It's not going to guess at the response type unless you send headers from the server. You can tell jQuery what response type to expect: `$.post(action, payload, callback, responseType);` by specifying "json" for responseType, jQuery will automatically attempt to turn the response into a JSON object. – crush Feb 05 '13 at 13:27
  • Both T.J and Bergi (below) have the proper answers on this subject I think. – crush Feb 05 '13 at 13:37
  • I actually really like your HTTP error code idea. I have read that a lot of stuff simply gets returned as success, regardless of it's success. Is it overkill to return an HTTP error for something as simple as a name not being found in a database? Is this more "RESTful" to do it this way? Would header("HTTP/1.0 404 Not Found") be the "correct" response for something like this? Or would a 500 be more appropriate? – K.K. Smith Feb 05 '13 at 13:58
  • 1
    @K.K.Smith: *"Generally I would echo back a simple string, or json_encode an array or object. Have I just been "lucky" that everything seems to have worked?"* A bit, your web server is probably set to default to `text/html` for PHP pages, and those get passed through as a string to the success handler, so if it's really JSON and you parse it as JSON, it was fairly harmless that it travelled with the wrong content type. – T.J. Crowder Feb 05 '13 at 14:06
  • 1
    @K.K.Smith: Re your questions about status codes, I've seen it well-argued each way. If you use a non-200 status code, 404 would be an appropriate response code if you were doing a `GET` for information on a user and the user ID/name/whatever given in the request is invalid. Sometimes people use 500, but that's for *unexpected* problems, so if the user is supplying the user ID/name/whatever, it's not appropriate (we expect users to get things wrong). I use 200 and an app-level success/fail flag, on the theory I'm separating concerns (HTTP vs. app), but again, I've seen it well-argued each way. – T.J. Crowder Feb 05 '13 at 14:08
4

Your script should either return a response that translates into a JavaScript equivalent of your PHP variables to make such comparisons possible or use HTTP status codes to convey an error condition.

Response handling

jQuery.ajax() and friends interpret the response (automatically by default) based on the response headers that you send, be it XML, JSON, etc.

The below code outputs a JSON formatted response:

header('Content-Type: application/json');
echo json_encode(array(
    'success' => true,
));

The output that is sent to the browser looks like this:

{"success": true}

Inside your success handler you can now use the following code:

if (response.success) { ... }

Error handling

jQuery.ajax() can also handle HTTP status code responses other than the regular 200 OK, e.g.:

header('404 Not found');
exit;

This will invoke your error handler:

$.ajax({
    url: ...,
    error: function(xhr, status, msg) {
      // xhr - see http://api.jquery.com/jQuery.ajax/#jqXHR
      // status - "error"
      // msg - "Not found"
      alert('Error code ' + xhr.code + ' encountered');
    }
});
Ja͢ck
  • 170,779
  • 38
  • 263
  • 309
  • This is interesting. I somehow thought that bool true/false was just a thing in itself. But I guess it makes sense that it is a completely different construction in different languages. The label true/false, is just the label. So I need to translate "PHP version of bool true" into "JS version of bool true". ... true into true. – K.K. Smith Feb 05 '13 at 13:13
  • 3
    Technically, just `true` or `false` on its own is invalid [JSON](http://json.org). The top-level of a JSON document **must** be an object or an array. Just `true` or `false` on their own is a valid JSON *fragment*, but not a valid JSON document (and some parsers are picky about it). – T.J. Crowder Feb 05 '13 at 13:15
  • @K.K.Smith Not exactly. AJAX calls return a string. The client (your web browser) translates that string. By default, jQuery's `$.post()` method translates that string into `plain text`. Therefore, if you output a string from PHP, you get a plain text string in jQuery. However, you have the option to specify to the `$.post()` method that you are expecting a `json` response. `You need to learn the difference between a string and a boolean`. – crush Feb 05 '13 at 13:16
  • @T.J.Crowder Hmm, that's true actually, it would be better to encapsulate the boolean in an object; answer updated. – Ja͢ck Feb 05 '13 at 13:18
  • 1
    @crush The difference is in the headers that you send; `application/json` has a meaning other than just plain text. – Ja͢ck Feb 05 '13 at 13:18
  • @Jack He can set the headers with PHP, or he can tell jQuery to expect a JSON object, in which case, jQuery will do `JSON.stringify` on the outputted string. `Sending the headers is both more efficient, and more robust - good point.` K.K.Smith is neither setting headers, nor telling jQuery to expect JSON. – crush Feb 05 '13 at 13:24
  • @K.K.Smith I've modified my answer a bit to have that boolean encapsulated inside an object; that way you can also extend the response later. – Ja͢ck Feb 05 '13 at 13:31
  • @crush I understand that the string "false" is truthy. As is any string. But when I return false from PHP (as opposed to echoing), I thought that still carried its "falsiness" over to the client. But I guess as soon as you launch it out of the server it is just text anyways. So it will either be interpreted as a plaintext string "false", which is truthy, or interpreted as JSON (in which case the simple string "false" wouldn't convey the boolean false). Do you know offhand how bool false is shown in a JSON encode? – K.K. Smith Feb 05 '13 at 13:31
  • 1
    If you `return false` from your PHP, then nothing is getting output to the response back to the client from the server because `return false` does not output anything. – crush Feb 05 '13 at 13:34
  • @crush That was a lightbulb moment. Of course you are right, but somehow I have been thinking of return true/false as return yes/no ... but it is more like return yes/ *not* return at all – K.K. Smith Feb 05 '13 at 13:38
3

Ajax calls expects a text returned by your scripts, when you return a php bool, it will not be outputted, so you need to echo "something", and its does not have to be "true" or "false"

phpalix
  • 679
  • 4
  • 8
  • *"when you return a php bool, it will not be outputted"* Sure it will. PHP's output function will turn it into a string and send it. This answer is also very vague and offers no real guidance on how to solve the problem, I'm surprised to see it upvoted so much. – T.J. Crowder Feb 05 '13 at 13:17
  • 1
    I think he means `return true;` as opposed to `echo true;` – crush Feb 05 '13 at 13:18
3

All depends on your server response. If you use appropriate MIME types, jQuery might automatically JSON.parse() the response for you, passing the boolean true to your callback. If it does not recognize JSON, it will pass the textual result "true" which you need to compare against:


// PHP:
header('Content-Type', 'application/json');
echo true; // or "true" or json_encode(true)

// JavaScript (with jQuery.ajax):
… function callback(response) {
    typeof response; // "boolean"
    if (response) {…}
} …

// PHP:
header('Content-Type', 'text/plain'); // or similar, also implicit
echo "true";

// JavaScript (with jQuery.ajax):
… function callback(response) {
    typeof response; // "string"
    if (response == "true") {…}
} …
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • If you expanded a little more here, it would probably be the top vote getter as you are hinting at the proper way to do this. – crush Feb 05 '13 at 13:25