Page 1 of 1

A generic handler for AJAX requests Use AJAX to replace, append, redirect the page or whatever. Rate Topic: -----

#1 moopet  Icon User is offline

  • binary decision maker
  • member icon

Reputation: 339
  • View blog
  • Posts: 1,185
  • Joined: 02-April 09

Posted 18 August 2010 - 01:56 PM

I'm going to talk about using AJAX to allow the server side scripts greater access to your browser. Specifically, to allow you to change the dom from the server using jQuery selectors. All without having to munge together javascript and get the browser to eval() it, which basically sucks.

Be warned that I'm not going to go into a lot of detail about how to run the server side of it except a tiny snippet.

A lot of people seem to give up on AJAX because they get into hairy messes with functions hard-coded into everything that needs to talk to the server. One way forward is to make a general AJAX handler function such as the one I'm about to describe.

To start with, here's the function in its entirety. I'll go through it line-by-line and give examples of use afterwards. It's very basic and only allows for four action types: replace, append, redirect and debug.
function jsonRequest(href, dict, callback) {
    $.post(href, dict, function(data) {
        if (data) {
            if (typeof(data.error) != 'undefined')
                if (typeof(console) != 'undefined') {
                    console.log('debug: ' + data.error);
                }
                delete data['debug'];
            }

            if (typeof(data.replace) != 'undefined') {
                $.each(data.replace, function(selector, content) {
                    if ($(selector).length) {
                        debug('jsonRequest: replacing ' + selector);
                        $(selector).before(content).remove();
                    }
                });
                delete data['replace'];
            }

            if (typeof(data.append) != 'undefined') {
                $.each(data.append, function(selector, content) {
                    if ($(selector).length) {
                        debug('jsonRequest: appending ' + selector);
                        $(selector).append(content);
                    }
                });
                delete data['append'];
            }

            if (typeof(data.redirect) != 'undefined') {
                location.href = data.redirect;
            } else if (typeof(callback) == 'function') {
                callback(data);
            }
        }

    }, 'json');
}



Ok, here goes:
function jsonRequest(href, dict, callback) {
    $.post(href, dict, function(data) {
...
    }, 'json');
}


This is the most common method of making an ajax resuest with jQuery. I use "post" for all my requests, but there may be |citation needed| occasions where you need to use "get". Really I'd avoid it though, because if you can "get" something from the server which might for example be a request to delete an item from your database, then it's possible that a web spider could follow the link and perform the same deletion. Unlikely, maybe, and this example depends on an entire url being visible in your source, but it's easier to avoid the risk altogether by just making the request into a "post" in the first place.
Our function takes three arguments, the same as jQuery's post(). This means you can use it as a drop-in replacement for any ajax requests that expect their data to be returned as JSON. JSON, if you're not familiar with it, is a Brilliant Thing. Here's an example of a JSON object:
ideal_partner = { girth: 82, power: 166, name: 'freddy' };
alert(ideal_partner.girth);  // displays "82"


Which should be self-explanatory. It's like a dictionary in Python or an associative array in PHP, where key/value pairs exist. The keys must be unique, but the values can be other JSON objects, allowing multiple levels of nesting. It's basically great, and it's vital to this whole tale.

Next up we have the first action, "debug":
            if (typeof(data.error) != 'undefined')
                if (typeof(console) != 'undefined') {
                    console.log('debug: ' + data.error);
                }
                delete data['debug'];
            }



This is about as trivial as an action can be. If we receive anything back from the server with a key of "debug" we spit it out to the console - of course this only works if we have a console to log stuff to. This really means Firefox with firebug installed or one of the webkit browsers.
It's not strictly necessary to delete the debug key from the data object, but there is a sane reason for this, and it's that if there has been a callback function specified, we want to pass it data without anything extra in it. Same thing could be achieved in other ways, this is just one, but it's nice to keep things neat.

The next two actions are nearly identical, "replace" and "append":
            if (typeof(data.replace) != 'undefined') {
                $.each(data.replace, function(selector, content) {
                    if ($(selector).length) {
                        debug('jsonRequest: replacing ' + selector);
                        $(selector).before(content).remove();
                    }
                });
                delete data['replace'];
            }

            if (typeof(data.append) != 'undefined') {
                $.each(data.append, function(selector, content) {
                    if ($(selector).length) {
                        debug('jsonRequest: appending ' + selector);
                        $(selector).append(content);
                    }
                });
                delete data['append'];
            }


The only difference between these two should be obvious. Replacing an element using jQuery is accomplished pretty simply by inserting the new content ahead of it then deleting the original, hence the before(content).remove() phrase.
What's neat here is that we're looping through a JSON object called "replace" and treating each key as a jQuery (or CSS3) selector, and each corresponding value as a snippet of HTML.

Next up:
            if (typeof(data.redirect) != 'undefined') {
                location.href = data.redirect;
            } else if (typeof(callback) == 'function') {
                callback(data);
            }


We respond to a redirect action by simply redirecting the browser page entirely. This probably isn't going to be obviously useful, but there are occasions when you're communicating over ajax and wish you could throw the user somewhere else. Example? Ok, what about if you detect that their session has expired? You might have an ajax poll every few minutes or so to check for alerts, and the user's session might expire (maybe they logged out in a different tab or from oauth or something). Your server-side code can tell the browser to send them back to the login page.
Finally, if there is no redirect action, forward the remaining data on to the callback function, if it exists. Why is this in an else block? Because you probably don't want some local function starting to do an animation or even a further ajax call wwhen the code logic obviously doesn't need anything else on this page.

here's a running example of a (not really that sensible) scenario:
setTimeout("jsonRequest('/ajax/check_mail.php')", 5 * 60 * 1000);

$('a.ajax_link').live('click', function() {
    jsonRequest($(this).attr('href'), { 'dom_id': $(this).attr('id'}, function() { alert('well, that worked'); });
    return false;
});


Every 5 minutes, we send nothing to the server, calling check_mail.php, and it might return the following:
{
    debug: 'Hey there hi there ho there',
    replace: {
                 '#mail_count': 'You have 99 new messages!',
                 '#warning': 'You have no space left in your mailbox!'
             }
    append: {
                '#wall': 'So-and-so wrote on your wall'
            }
}



and every time someone clicks on a link with the class "ajax_link" (I'm so original), we send:
{
    dom_id: 'id_i_am_a_navigation_link'
}


to the href of the link that was clicked. Whereupon the server knows the id of the calling link. I'm not going into how that could be useful, just use your imagination.

On the server side this is all fairly easy to arrange. For instance, in PHP you can make your response up of a nested array and just call the json_encode() function on it before printing it out:
$a = array();
$a['debug'] = 'Hey there hi there ho there';
$a['replace'] = array('#mail_count' => 'You have 99 new messages', '#warning' => 'You have no space left in your mailbox!');

echo json_encode($a);



Don't forget to set the headers. You're most likely to want them to be "application/json".

Other things you can do to extend this idea include finding the closest parent with a particular class and adding another class to it:
$('element-here').closest('.my-ajaxable-bit').addClass('busy');


and then removing that class once the request has been completed. If you play your CSS right, you can make a nice spinner effect over the element(s) you're playing with.

Is This A Good Question/Topic? 0
  • +

Page 1 of 1