Quick Guide to using drupal_add_tabledrag and enjoying jquery drag and drop loveliness
Mike Dixon
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 ...
}