How to use subgroups in drupal_add_tabledrag() I am trying to implement a form that is themed with drupal table drag using subgroups. My form consists of a list of 'employees' that need to be assigned to different 'departments'. The order of the employees does not matter once they are inside a department.

The admin/structure/block table is similar to what I am looking for but with just the select box for region and no weights.

I've looked through the documentation here: http://api.drupal.org/api/drupal/includes--common.inc/function/drupal_add_tabledrag/7 and I've also studied the admin/structure/block table code but after several hours of trying different combinations - I am stuck!

The block module uses custom JS and a template tpl file for outputting the table. I think this doesn't take full advantage of Drupal. Therefore, this solution should make use of theme_table and #ajax (for the region select fields).
If you want ajaxed example perhaps you can study the Display Suite UI.

In my opinion the easiest way to do this if you need similar functionality is just to use the block module tpl's and change the data presented inside it (from block region to your custom module regions)

to remove the weights, I think if you remove :

drupal_add_tabledrag('blocks', 'order', 'sibling', 'block-weight', 'block-weight-' . $region); 


it will remove the ability to drag and sort the weight.

some rough examples for "Drupal compliant" way :

note: this is VERY rough code, you will need to adjust it heavily


function theme_example(&$variables) {
  // build the header
  $header = array(
    '', // this will be hidden when table drag run
    '', // this will be hidden when table drag run
    t('Block Region'),
    t('Region Area'),
  );
  // enabled region
  //$regions = region_area_grab_region('enabled');
  // substitute this to what ever your module provides
  // this should be in $form array
  $regions = array('example_one', 'example_two', 'example_three');

  $region = array('example_block_one', 'example_block_two', 'example_block_three');

  // Add table javascript.
  drupal_add_js('misc/tableheader.js');
  drupal_add_js(drupal_get_path('module', 'block') . '/block.js');

  // take notice of the key that will be related to real options
  // in the select box, this should be in $form array
  $options = array();
  foreach ($regions as $key => $region) {
    $options[$region] = $region;
  }

  // add additional class here
  $attributes = array(
    'class' => array('draggable'),
  );


  // building the table rows
  $rows = array();

  // looping for each regions
  foreach ($regions as $region) {

    // this is the heart of the draggable
    // take good notice for the region-manager (the table id), region-area-weight (group of rows class)
    // and regionarea-weight- $region (unique row class), you will need to add this to the form array
    // element NOT in the table row

    // if you want to emulate the block page table drag, comment out the drupal_add_tabledrag
    drupal_add_tabledrag('region-manager', 'order', 'group', 'regionarea-weight', 'regionarea-weight-' . $region , $hidden = FALSE);
    // build the region row

    // replace this with your form element array eg $variables['form']['whatever']
    $elements = regionarea_build_admin_region_form($region, $form, $form_state);

    $row = array();
    $row[] = '';
    $row[] = drupal_render($elements[$region['name']]['weight']); // replace this to actual form array for the weight
    $row[] = $elements[$region['name']]['name']['#value']; // replace this to actual form array for the value / title
    $row[] = drupal_render($elements[$region['name']]['enabled']); // optional
    $row = array_merge(array('data' => $row), $attributes); // merge the array, add draggable class
    $rows[] = $row; // build the row

    // ----------------------------------------------------------------------------------------------------------------- //
    // Usually up to this point is enough for just normal draggable, only continue if you have a sub child to drag
    // ----------------------------------------------------------------------------------------------------------------- //

    // build the block regions
    // now we looping for the sub child AKA regions as in the block region page
    foreach($region['regions'] as $regionkey => $blockregion) {
      // add two table drag, one for weight the other for 'region'
      drupal_add_tabledrag('region-manager', 'match', 'sibling', 'region-select', 'region-' . $blockregion, NULL, FALSE);
      drupal_add_tabledrag('region-manager', 'order', 'sibling', 'region-weight', 'weight-' . $blockregion);

      // replace this with your form element array eg $variables['form']['whatever']['children']
      $elements = regionarea_build_admin_blockregion_form($blockregion, $regionkey, $options, $form, $form_state);

      // build the current row
      $row = array();
      $row[] = '';
      $row[] = drupal_render($elements[$blockregion]['weight']);
      $row[] = $elements[$blockregion]['name']['#value'];
      $row[] = drupal_render($elements[$blockregion]['regions']);

      $row = array_merge(array('data' => $row), $attributes);
      $rows[] = $row;
    }

  }

  // some options to pass to the theme_table
  $element = array(
    '#empty' => t('There are no region area available'),
    '#attributes' => array(
      'id' => 'region-manager',
    )
  );

  // build the theme
  return theme('table', array('header' => $header, 'rows' => $rows, 'empty' => $element['#empty'], 'attributes' => $element['#attributes'])),
}