views:

49

answers:

1

I know how to get an AJAX response:

$.post( '/action', 
        { actiontodo: 'insert' } 
        function (data) { alert(data); } );

Int the action.php (server side):

<?php 
       if ($_POST['actiontodo'] == 'insert') 
       { 
           doInsertAction(); 
           echo "inserted"; 
       } 
?>

Finally the output of this code is an alert BOX with the word: inserted.

BUT, without ajax, I have two ways to solve this (in the server side):

ONE:

<?php 

if ($_POST['actiontodo'] == 'insert') { 
    doInsertAction(); 
    header( "Location: " . $_SERVER['HTTP_REFERER'] . " &response=inserted"  ); 
} ?>

TWO:

<?php
session_start();
if ($_POST['actiontodo'] == 'insert') {
    doInsertAction();
    $_SESSION['response'] = 'inserted';
}
header( "Location: " . $_SERVER['HTTP_REFERER'] );
?>

Returning to the page I get the answer from the SESSION or from GET and shows the alert.

I like more the ONE solution, but each solution has a problem:

ONE problem:

The returning URL is : http://www.foo.com/myrefererurl&amp;response=inserted

If you types this URL without using the form, you will see the alert BOX each time you will refresh the page. The question is: How to show the message only ONE time? (ONLY AFTER THE FORM ACTION)

TWO problem:

The SESSION now has the value inserted ($_SESSION['response']), when the page returns from the action obviously the solution maybe delete this value of the session like: unset( $_SESSION['response'], but SUPPOSE the UNSET do not reached for any reason (connection failure or navigation stopped by the user, etc), when you go to another form in other page the alert will showed because the $_SESSION['response'] still exists (in another form without submit it and has nothing to do with that response). Inclusively WITH GET &response=inserted in another URL the problem will exists too.

I hope you understand this questions and bring a BEST WAY solution. Basically the question is how to control that responses......

+2  A: 

Unobtrusive JS, or "progressive enhancement" is the way to go.

Step 1:

Build your page first to work without JavaScript. Let's say you have a simple application where a user selects something and hits submit. Depending on the selection, you will either display a helpful error message above the form or you'll update the page with the correct output and hide (or get rid of) the form. Build this page like you would for AJAX, but do not script anything yet.

Here's your page:

<html>
<head>
    <style type="text/css">
        p#feedback { display:none;}
    </style>
</head>
<body>
    <div id="feedback"></div>
    <div id="form">
        <form action="getaction.php" method="post" id="actionform">
            <select name="requestedAction">
                <option value="foo">Do Foo</option>
                <option value="bar">Do Bar</option>
            </select>
            <input type="submit">
        </form>
    </div>
</body>
</html>

On a successful submission. the server will get a request with one $_POST value: requestedAction=foo (or bar). Based on this, your server script will construct a new page with everything from <html> to </html>.

At this point, you have a page that works in any non-JS-enabled browser. Old fashioned. Very reliable.

Step 2

Add the scripting to override the default submit behavior. Grab the data you need from the page and construct an AJAX submission. The only difference between this and the submission above is that you will add a flag telling the server that the request is coming via AJAX and to send back only the needed message (you could also send it to a different script). The server script will basically go through the same logic as above, but rather than building the entire page, it only sends back the message string and leaves it to AJAX to put that data in the right place. Your response could be just a text fragment, a block of HTML or an XML data structure. It depends on your needs.

<script type="text/javascript">
    $(enhance); // at onDOMReady, run the enhance function

    function enhance() {
        // Override the default form submission behavior:
        $('form#actionform').bind('submit',doSubmit);
    };
    function doSubmit(event) {
        $.ajax(
            {
                type:'POST',
                url:'/path/to/getaction.php',
                data:'request=' + $('form#actionform select[name=requestedAction]').val() + '&type=ajax',
                success:fnCallback
            }   
        );
        // Kill the submit action so the user doesn't leave the page
        event.preventDefault();
    };
    function fnCallback(xhr) {
        var strResponse = xhr.responseText; 
        if (strResponse === "error") {
            $('div#feedback').text("There was an error. Please try again.");
        }
        else {
            $('div#feedback').text(strResponse);
            $('div#form').hide();
        }
    };
</script>

In this case, the AJAX submission will be identifiable to the server because there is a second POST parameter of type=ajax.

A site that does this really unbelievably well on a very big scale is ESPN. Turn off JS and check out their main story headlines under the big picture. The behavior is identical to their AJAX-enabled page and aside from the video not working, you really would never know if your JS was on or off. There's basically no way to build a site like this without starting from dumb HTML and building up.

Andrew
When you say: "Based on this, your server script will construct a new page with everything from <html> to </html>." I think, this is the final solution, BUT: What happens with the URL, I don't want the new URL will be /getaction.php, this means that we need to put in the action of the form this: action="<?php echo selfUrl(); ?>", where selfUrl returns the current URL of the page (including parameters) and at the top of the script process the action IN CASE of a request ... . Are you agree with that?
Cris Hong Kong CRISHK
I'm getting into a new trouble with this solution, when the user refresh tha page, gets a message to confirm if resend the form or not...., beacuse is the same URL ...
Cris Hong Kong CRISHK
Regarding the double-posting, that's a very old problem. There's a simple solution to it: in the form page, add a hidden input that either has a session token (if your server allows sessions), a timestamp, a GUID or some other unique identifier. If your server supports tokens, you can simply compare them and kill the second request. Or you can save the unique identifier with the user's submission details and do a check to see if that number already exists. It's an extra DB/filesystem hit, but that's how you do it.
Andrew
If you really need to redirect the user to a different URL (which is a very common solution), then do use a `Location:` redirect. There's no harm in that. I personally write my applications (or the ones that have user interaction) so that all requests go through one single URL (like 'index.php') and I never use URL parameters. I find it's much easier handling security, so I really don't do it any other way.
Andrew