We are finding that the feature exciting most end users in Drupal 6 is the lovely new jquery based drag and drop, as seen on the blocks and menu edit pages - we will be quite happy never have to explain the concept of "weights" again. The best news is that you can add this functionality to your own forms for free - and here is how.
Build and theme the form
We are assuming your vaguely familiar with the form API - you can brush up here http://api.drupal.org/api/file/developer/topics/forms_api.html - so we won't go into too much detail here. Essentially we need to create a form that will be themed into a table, each row in the table will need a form element capable of holding the "weight" or "order" value.
function example_form(&$form_state){
//fetch the data from the DB
$result = db_query("SELECT id, value1, value2, weight
FROM {foo}
ORDER BY weight ASC");
while ($row = db_fetch_object($result)){
//create a partial table row containing the data from the table
$data = array(
$row->value1,
$row->value2
);
//add our static "row" data into a form value
$form['rows'][$row->id]['data']=array(
'#type' => 'value',
'#value' => $data
);
//now create the weight form element.
//NOTE how we add the id into the element key
$form['rows'][$row->id]['weight-'.$row->id]=array(
'#type'=>'textfield',
'#size'=>5,
'#default_value'=>$weight,
//add a specific class in here - we need this later
'#attributes' => array('class'=>'weight'),
);
}
//Don't forget the submit button
$form['submit']=array(
'#type'=>'submit',
'#value'=>t('Save changes'),
);
return $form;
}
That should create a pretty basic and ugly form - we now need to theme this as a table
function theme_example_form($form){
//loop through each "row" in the table array
foreach($form['rows'] as $id => $row){
//we are only interested in numeric keys
if (intval($id)){
$this_row = $row['data']['#value'];
//Add the weight field to the row
$this_row[] = drupal_render($form['rows'][$id]['weight-'.$sid]);
//Add the row to the array of rows
$table_rows[] = array('data'=>$this_row, 'class'=>'draggable');
}
}
//Make sure the header count matches the column count
$header=array(
"Value1","Value2","Order"
);
$output = theme('table',$header,$table_rows,array('id'=>'example-table'));
$output .= drupal_render($form);
// Call add_tabledrag to add and setup the JS for us
// The key thing here is the first param - the table ID
// and the 4th param, the class of the form item which holds the weight
drupal_add_tabledrag('example-table', 'order', 'sibling', 'weight');
return $output;
}
Don't forget - we are in Drupal 6 land now so we need to register our theme function before it will take affect (how many times have I forgotten this already!)
function example_module_theme() {
return array(
'example_form' => array(
'arguments' => array('form' => NULL),
),
);
}
Handle the submit
We should now have a working drag and drop enabled form themed as a table, we now need to handle the submit and store our new weight values.
function example_form_submit($form, &$form_state) {
foreach($form_state['values'] as $key=>$data){
//we are only interested in weight elements
if (substr($key,0,6)=='weight'){
//cunningly we have the DB id of the row in the element name
$id = str_replace('weight-','',$key);
db_query("UPDATE {foo} SET weight=%d WHERE id=%d",$data,$id);
}
}
//optionally set the redirect value in form_submit ...
}

All articles feed
Comments
There is a specific type 'weight' in the Drupal API for cases like this - I suggest you use it rather than 'textfield'.
So the form field should be:
$form['rows'][$row->id]['weight-'.$row->id]=array(
'#type'=>'weight',
'#default_value'=>$weight,
'#attributes' => array('class'=>'weight'),
);
The advantage of using 'weight' is that when JS is turned off, the user gets a nice dropdown box with weights to choose.
@Shaun Ressler
It performs the write to the database with the new weights in the function: example_form_submit
If it's not working for you, start your debugging there.
How to use this function to make a page the same: admin/build/menu-customize/navigation:
*root
*parent1
*parent2
*children1
*leaf
*parent3
......
Thank you for advance
Thanks for this posting and I used this function into my websites and now problems solved!
There are a few errors in this code -- double-check it before using it on your own site.
--Cliff Smith
Great article! I found a minor error in the theme_example_form() function. The $sid variable should be $id in line 9. Also, a follow up article on how to create a table with children would be nice.
Newbie here . Very helpful. One thing not real clear is where code for form submit function gets put, how it gets called , and where the the function is called that actually triggers rendering the form .
IE, i think you call in a template or module menu callback or somewhere that is page is generated. :
Thanks
Great intro. I am missing something, though. You use the variable $weight but I do not see where it gets its value.
Great article! Very helpful... The tables are now appearing correctly for me, but the weight values are not being updated/saved at all... Nothing in the $form_state array reflects the appropriate weights on submit. Is there something missing somewhere?
Thanks,
Shaun
Thanks for this posting and I used this function into my websites and now problems solved!
Regards,
Sharon
Careful not to give your table the same id as you're form name (e.g. 'test-table' for table id, 'test_table' for form name) like I did. You'll end up wondering why you get obscure "this.table.tBodies is undefined" javascript errors.
Cheers got this to work with the new jQuery
Want to explain the concept of weights for drupal once more? only kidding :)