Professional Documents
Culture Documents
By Quentin Zervaas, 23 February 2006, Ajax, JavaScript, PHP, Prototype, Scriptaculous (2 comments)
Introduction
You might have been in a situation before where you had a list of items in your database that needed to be output in a specific order. These items could be anything: perhaps a listing of your favourite movies or your favourite books. For whatever reason, you want them ordered in a custom way that cant be determined automatically (such as alphabetical). This article covers the implementation of a system that lets you easily define the order of such a list. Traditionally, implementations of such functionality involve you clicking a move up, move down, move to top, or move to bottom button that switches the order the items (one item at a time). Or perhaps each item has a text box with a number in it, that by changing the numbers you can change the order of the list. In any case, these methods are much more difficult to use than they should be. In this article, well create a drag drop system using JavaScript that will let you drag an item to its new position, and then save the new order as soon as you drop the item. To achieve the Ajax effects (that is, the drag/drop effect, and the seamless saving of ordering data), we will be using the Prototype and Scriptaculous libraries. Firstly, we will create a database table (compatible with MySQL and PostgreSQL) and populate it with data. Then we will output our list and apply the drag and drop effects to it. Finally, we will deal with the saving of the new ordering data. For our example, we will use a list of favourite movies, and implement functionality to change the order of our movies.
Database data
Listing 3 listing-3.sql
insert into movies (title) values ('American Pie'); insert into movies (title) values ('Die Hard'); insert into movies (title) values ('Clerks');
?>
?>
Installing Scriptaculous
Since we are using Scriptaculous to create the drag/drop effect, we must now download and install it. Note that we also need the Prototype library, however, this is included with the Scriptaculous download.
This example uses Scriptaculous 1.5.3. Once downloaded, extract the library in the directory where you saved index.php. You may save this elsewhere, but we will assume this is where you have saved it.
The name _movies_list_ refers to the ID of our unordered list. There are many more options and effects that can be applied, but the default options work just fine for what were doing. You can always read the Scriptaculous documentation for more options.
Note that we also added an ID to each list item, as these are the values that will be passed to the form. Note that these IDs and the ID of the list should use underscores as separators, not hyphens. So at this point, if you view this page, you should be able to drag the items in your list up and down! Cool eh?
Here we invoke the Prototype librarys Ajax request handler to call processor.php. Additionally, we use the serialize() method on the Scriptaculous Sortable object to create the POST variable we access in processor.php. Finally, we modify our list creation to tell it about this updateOrder() callback:
Listing 16 listing-16.js
Sortable.create('movies_list', { onUpdate : updateOrder });
The second parameter to Sortable.create() is an optional list of extra parameters. In this case we are just specifying the onUpdate parameter, which tells Sortable which function to call when the list is changed.
exit;
$movies = getMovies(); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1strict.dtd"> <html> <head> <title>phpRiot Sortable Lists</title> <link rel="stylesheet" type="text/css" href="styles.css" /> <script type="text/javascript" src="scriptaculous-js1.5.3/lib/prototype.js"></script> <script type="text/javascript" src="scriptaculous-js1.5.3/src/scriptaculous.js"></script> </head> <body> <h1>phpRiot Sortable Lists</h1> <ul id="movies_list" class="sortable-list"> <?php foreach ($movies as $movie_id => $title) { ?> <li id="movie_<?= $movie_id ?>"><?= $title ?></li> <?php } ?> </ul> <script type="text/javascript"> function updateOrder() { var options = { method : 'post', parameters : Sortable.serialize('movies_list') }; } new Ajax.Request('processor.php', options);
Now, when you visit this page, you will see the list just as you did before, but now when you drag an item to a new location, it will be saved in the database. If you dont believe me, try dragging an item, closing your browser, then reloading the page. The order will be just as you left it after dragging the item.
Next: Summary
Summary
In this article we learned how to create a sortable list using PHP and Ajax. We used Scriptaculous and Prototype libraries to make light work of our JavaScript requirements (the sorting and Ajax requests), as these libraries provide a very powerful and simple interface to advanced features and effects.
Error handling
We didnt deal with error handling at all in this article, for the sake of simplicity. Specifically, we didnt specify what would happen if the update didnt work. If the update failed, the list would appear to be updated, but when you refreshed the list it would be the old state. One possible way to handle this would be to send a success/failure indication from processor.php, and then to read this response in index.php, rolling back the drag and drop if failure was returned.
Extra features
When you update the list, the saving of the new ordering is a very quick process, but it is possible that sometimes it could take longer due to latency or server load. As such, you might think about showing then hiding a message while performing the update. To do this, you would make the message appear when updateOrder() is called, and then create another function to hide the message once complete. This is achieved by specifying the onComplete parameter in the options array for the Ajax request. Heres an example:
Listing 18 listing-18.js
function updateOrder() { // turn on update message here var options = { method : 'post', parameters : Sortable.serialize('movies_list'), onComplete : function(request) { // turn off update message here }
Ill leave this as an exercise for you to complete. Hint: create a div which you initially set the CSS display property to none. Then set it to block to show the div, and set it back to none to hide it again.