JavaScript Drag'nDrop lists?

I have a MySQL based table in my website with some info. I would like to be able to reorder them with JavaScript and then I would simply hit Submit and then some PHP code would put that in the database.

After some Googling I saw this and this sites that show how to do that, but since I’m not so good in JS (in fact I barely know anything) and those sites don’t really explain good enough to me how to do this I was hoping that you guys could.

I like the later tutorial better, because they also have some Edit In Place something, but they don’t explain anything at all.

Could you explain to me how this is done?

Thank you.


freewaytalk mailing list
email@hidden
Update your subscriptions at:
http://freewaytalk.net/person/options

I do this in quite a few sites that I work on. The Scriptaculous
library has a very neat system called Sortable which does the hard
part. You can test this out in Freeway by adding the Protaculous
Action to your page, setting the Library picker to scriptaculous,
making a list on your page, and pasting the following code into the
first Function Body dialog in Protaculous:

var myList = $('nameOfTheBoxYourListIsIn').down('ul');
Sortable.create(myList,{});

Change the long-winded box name above to be the actual name of the
HTML box containing the list as noted in the Title field in Freeway’s
inspector.

That’s it – preview in a browser, and you will be able to drag the
list items around to change their order. But that’s all it will do, if
you refresh the page, the list will be back where it started.

So to take care of that problem, we need to make some changes to your
database to support this method.

In your database, add a column to your table to hold the ordering
information. I usually use an int(4) or something like that, called
position. (The name is not important.)

Make sure that your regular display code uses that column as its
primary sort order. Also make sure that each row of your database has
a numeric ID column.

Now make a new script which can access your database and accept a
POST, and write to the database. My example, which follows, is quite
terse because the framework I use does all the heavy lifting. Where
you see $item->save(), take that to mean the usual five lines of code
to update a MySQL database from PHP.

<?php require_once('config.inc.php'); include(APP_ROOT . '/models/people_model.php'); include(APP_ROOT . '/models/stories_model.php'); if(isset($_COOKIE['c2'])){ if($session = ActiveRecord::FindFirst('people','session = "' . $_COOKIE['c2'] . '" AND role IN ("author","admin")')){ foreach($_POST['sort_list'] as $k=>$v){ if($item = ActiveRecord::FindById('stories',$v)) { $item->position = $k+1; $item->save(); } } } } print 'finished'; ?>

So this script, which sits separate from the rest of your site, is
what the JavaScript library will contact to update the database with
the latest sort order. We’ll send a call to this script every time a
drag event finishes. That way, the database will always be up-to-date
with the current state of your page. In this example, I’ve named this
script ‘ajax_update_order.php’.

Now, the JavaScript to make this go:

document.observe('dom:loaded',function(){
	$('message').hide();
	Sortable.create('sort_list',{
		onUpdate: function(){
			new Ajax.Request('ajax_update_order.php',{
				parameters: Sortable.serialize('sort_list'),
				evalScripts:true,
				onCreate: function(transport){
					$('message').show().update('<img src="Resources/spinner.gif"  
height="16" width="16" alt="" />');
				},
				onComplete: function(transport){
					$('message').update('Changes saved!');
					new Effect.Highlight('message');
					new Effect.Fade('message',{delay:1});
				}
			})
		}
	});
});

The first line of this script sets up a “listener” that waits until
the entire page structure has loaded into memory, then fires the rest
of the script. The next line hides a DIV called ‘message’, which is
where I will update the user with the progress of the script. The next
line takes an unordered list with the ID ‘sort_list’ and makes it
sortable. And the nested functions after that define what will happen
when that list is sorted. onUpdate is an event that fires when the
list has been sorted. When it does, we will send a form request using
Ajax.Request to the ajax_update_order.php script. That script will
receive a POST body containing a variable named the same as your
list’s id, which will be an array of the list item IDs in the order in
which they appear on the page. This array is generated by the
Sortable.serialize function in the JavaScript – note that it also
takes the name of the list as an argument. If you look at the PHP
block above, you’ll see how this POST gets written back to the database.

The only wrinkle to this part of the process is that you must give
each list item in your UL an unique ID, and that ID must follow this
naming convention:

someString_N

…where someString is just any bit of text you like (since IDs cannot
begin with numerals), and the one and only underscore in the ID is
followed by the numerical ID of the database row that the list item
contains.

<li id="p_60">The Circle</li>

Since you are already writing out the list from your database, this
shouldn’t be anything too challenging to add to your current output
code.

The two functions within the Ajax.Request body are there to manage the
user interface. The first is fired when the request is sent to the
server, and updates the message DIV with a spinning graphic to show
that something is happening. The second happens after the update has
been processed, and sets a message saying that the change has been
committed to the database, and then fades that message away.

I’ll write some more about this later, but this should get you chewing
on a solution for now.

Walter

On Dec 14, 2008, at 11:11 AM, Egill Sigurdur wrote:

I have a MySQL based table in my website with some info. I would
like to be able to reorder them with JavaScript and then I would
simply hit Submit and then some PHP code would put that in the
database.


freewaytalk mailing list
email@hidden
Update your subscriptions at:
http://freewaytalk.net/person/options

Err, don’t seem to get my list drag’ndrop-able in the first place. When I go to the Console error log in the Web Inspector in Safari, I get told that ‘value doesn’t exist’ in the JS code.


freewaytalk mailing list
email@hidden
Update your subscriptions at:
http://freewaytalk.net/person/options

Could you post a link to your test page, I can tell more about what’s
going on if I can see the error in Firebug.

Walter

On Jan 17, 2009, at 12:31 PM, Egill Sigurdur wrote:

Err, don’t seem to get my list drag’ndrop-able in the first place.
When I go to the Console error log in the Web Inspector in Safari, I
get told that ‘value doesn’t exist’ in the JS code.


freewaytalk mailing list
email@hidden
Update your subscriptions at:
http://freewaytalk.net/person/options

I finally found out what had been wrong (it’s kinda stupid so I’m not gonna say what) and it works fine.

I read some tutorials and ended up by copying some of the source from this site that had added something to that tutorial on how to do drag & drop.

It took me a looong time to read trough the code and figure this out (since I pretty much suck at JavaScript) but finally got it working (see the result).

Now, I do not plan on using anything magical like Ajax, a Submit button is fine.
The info is kept in a MySQL database with an id row called ‘artid’, but I have absolutely no idea of how to submit the data from the drag & drop thing.

Thanks.










Here is the site I am trying to read something out from:

http://tool-man.org/examples/sorting.html


freewaytalk mailing list
email@hidden
Update your subscriptions at:
http://freewaytalk.net/person/options

Wow, that looks like a lot of work, compared with the Scriptaculous
drag and drop.

  1. Draw a Markup Item on the page where you want your list to appear.
  2. Apply Protaculous to the page, select scriptaculous-packed from the
    Library picker.
  3. Enter the Markup Item and add your code to draw the list. Make sure
    that each list item generated by your code has a unique ID made up of
    some string, like ‘item’ followed by an underscore ‘_’ and then a
    number. So if you had a list of four things, they would look like this:
<ul id="sort_me">
<li id="item_23">Item 23</li>
<li id="item_28">Item 28</li>
<li id="item_16">Item 16</li>
<li id="item_4">Item 4</li>
</ul>
  1. Somewhere on the page, draw a colored box, and note its name in the
    Inspector (item2 in this example). Make sure this box is a layer, but
    it doesn’t matter if it is a DIV or a graphic.
  2. In the Protaculous Action, click on either of the Function Body
    buttons and enter the following:
Sortable.create('sort_me',{});
$('item2').observe('click',function(evt){
	Event.stop(evt);
	alert(Sortable.serialize('sort_me'));
});
  1. Publish this somewhere, and preview it in a browser. Drag and drop
    the elements of the list, and then click on the colored square. You
    will see a list of the elements in their current order. Drag and drop
    some more, then click again. You will see the new order. So that’s one
    include and five lines of code to make a sortable list that can report
    its current order when asked.

To get this to your server, you can do one of two things. The way that
Scriptaculous is wired (and thus the easiest way to get things done)
is to use an Ajax callback.

On the server, make a new script (mine is called
ajax_update_order.php). Put your equivalent to this code in it (mine
is extremely brief, because it uses my framework. There’s hundreds of
lines of code being invoked somewhere to make this work:

<?php
require_once('config.inc.php');
include(APP_ROOT . '/models/stories_model.php');
	foreach($_POST['sort_me'] as $k=>$v){
		if($item = ActiveRecord::FindById('stories',$v)) {
			//position is an integer column, used to sort the list
			$item->position = $k+1;
			$item->save();
		}
	}
}
print 'finished';
?>

Modify the JavaScript that you pasted into the Action interface to
read as follows:

Sortable.create('sort_me',{
	onUpdate: function(){
		new Ajax.Request('ajax_update_order.php',{
			parameters: Sortable.serialize('sort_me')
		})
	}
});

That’s it. Now every time you change the list in any way by dragging
and dropping, a new server request will go off to the
ajax_update_order script, and each element in the list will be updated
to its new order. (Specifically, a column called ‘position’ will be
updated with the new order number. Your code for drawing the list will
need to sort by this column when drawing the list again for a new page
view.)

The harder way to do this is to have a similar script on the server,
but rather than making the update after each drag, you would have a
separate form submitted to your handler. Using JavaScript, you would
capture that form’s submit event, stop it, calculate the new order,
and then submit the form including that information:

$('my_form').observe('submit', function(evt){
	Event.stop(evt);
	$('my_form').insert(
		new Element('input',{
			name:'sort_me',
			value:Sortable.serialize('sort_me')
		})
	);
	$('my_form').submit();
});

The logic on your form handler would be similar to the ajax callback
function listed above. The value of sort_me will be an array. The
index of each element of that array would be its position, and the
value would be its numerical ID.

Hope this helps, post questions in the Dynamo list if you need more.

Walter

On Jan 31, 2009, at 12:53 PM, Egill Sigurdur wrote:

Now, I do not plan on using anything magical like Ajax, a Submit
button is fine.
The info is kept in a MySQL database with an id row called ‘artid’,
but I have absolutely no idea of how to submit the data from the
drag & drop thing.


freewaytalk mailing list
email@hidden
Update your subscriptions at:
http://freewaytalk.net/person/options