Writing forms in tables

When you want your form elements to be presented in tables (as, more generally, whenever you want to customize the presentation of your form), you follow a two-step process. First, you generate the appropriate form elements. Then, when it comes time to present the form, you pass it through a theme.

Good examples of how to do this are in the issue.inc file in the Project module.

The simplest is used to present the issue filtering interface, seen at the top of the page http://drupal.org/project/issues. Note that the form elements here are enclosed in a table, so that they appear beside each other in a row.

To accomplish this, the elements are first generated in the function project_issue_query_result():

<?php
// Make quick search form:
$form['projects'] = array(
 
'#type'=> 'select',
 
'#title' => t('Project'),
 
'#default_value' => $query->projects,
 
'#options' => $projects,
);
// etc.
?>

A drupal_get_form() call generates the form output:

<?php
$group
.= drupal_get_form('project_issue_query_result_quick_search', $form);
?>

Normally this would return a standard-formatted form, but in this case the module includes a theme function to customize the output of this form: theme_project_issue_query_result_quick_search().

The theme function simply takes the form elements and generates an array of cells, then outputs the result as a table:

<?php
$rows
[] = array(
 
form_render($form['projects']),
 
// etc.
);
// ...
$output = theme('table', array(), $rows);

// Render the remainder of the form.
// This is crucial for proper function.
$output .= form_render($form);
return
$output;
?>

Look at other forms in issue.inc for more complex examples, e.g., project_issue_admin_states_page(), which uses nested arrays to generate multi-line tables with one row per record.

Tip: If your theme function requires extra data, include it in the forms array:

<?php
$form
['data'] = array();
$form['data']['#message'] = t('A message...');
?>

One more way

iDanil - July 28, 2006 - 09:15

There is more simple way to put your form in a table - just use '#prefix' and '#suffix' properties.
for example:

$form['city'] = array(
  '#type' => 'select',
  '#title' => $list_titles['city'],
  '#options' => $list_cities,
  '#prefix' => '<table height= \'30\' width=\'80%\'><tr><td width=\'100\'>',
  '#suffix' => '</td>', '#required' => TRUE,
  '#default_value'=> $node->city
  ); 
  $form['adr'] = array('#type' => 'textfield', '#title' => $list_titles['adr'], '#required' => TRUE,
  '#prefix' => '<td>',
  '#suffix' => '</td></tr></table>',
  '#default_value'=> $node->adr
  );

A clearer tables example

dayre - September 19, 2006 - 01:58

I didn't find the project issue example all that helpful, the core input filters module was easier to understand. Notice the loading of the form array in the overview function and how it is then themed in the theme function.

<?php
function filter_admin_overview() {

 
// Overview of all formats.
 
$formats = filter_formats();
 
$error = false;

 
$rows = array();
  foreach (
$formats as $id => $format) {
   
$roles = array();
    foreach (
user_roles() as $rid => $name) {
     
// Prepare a roles array with roles that may access the filter
     
if (strstr($format->roles, ",$rid,")) {
       
$roles[] = $name;
      }
    }
   
$row = array();
   
$default = ($id == variable_get('filter_default_format', 1));
   
$options[$id] = '';
   
$form[$format->name]['id'] = array('#value' => $id);
   
$form[$format->name]['roles'] = array('#value' => $default ? t('All roles may use default format') : ($roles ? implode(', ',$roles) : t('No roles may use this format')));
   
$form[$format->name]['configure'] = array('#value' => l(t('configure'), 'admin/filters/'. $id));
   
$form[$format->name]['delete'] = array('#value' => $default ? '' : l(t('delete'), 'admin/filters/delete/'. $id));
  }
 
$form['default'] = array('#type' => 'radios', '#options' => $options, '#default_value' => variable_get('filter_default_format', 1));
 
$form['submit'] = array('#type' => 'submit', '#value' => t('Set default format'));
  return
drupal_get_form('filter_admin_overview', $form);
}


function
theme_filter_admin_overview($form) {
  foreach (
$form as $name => $element) {
    if (isset(
$element['roles']) && is_array($element['roles'])) {
     
$rows[] = array(
       
form_render($form['default'][$element['id']['#value']]),
       
check_plain($name),
       
form_render($element['roles']),
       
form_render($element['configure']),
       
form_render($element['delete'])
      );
      unset(
$form[$name]);
    }
  }
 
$header = array(t('Default'), t('Name'), t('Roles'), array('data' => t('Operations'), 'colspan' => 2));
 
$output = theme('table', $header, $rows);
 
$output .= form_render($form);

  return
$output;
}
?>

form_render no longer exists

Shiny - December 6, 2007 - 04:00

form_render no longer exists in Drupal 5+

-------------------------------------------------------
http://coffee.geek.nz

Complex example (Drupal 5+)

Comitto - December 13, 2007 - 09:12

<?php
function comitto_form() {
 
// ... form fields
 
$form['set1'] = array (
   
'#type' => 'fieldset',
   
'#title' => t('Fieldset1'),
   
'#theme' => 'comitto_form_table'
 
);
 
$form['set1']['name'] = array (
   
'#type' => 'textfield',
   
'#title' => t('Name')
  )
 
$form['set1']['email'] = array (
   
'#type' => 'textfield',
   
'#title' => t('e-mail')
  )
 
// ... more form fields
 
return $form;
}

function
theme_comitto_form_table(&$form) {
 
$content = '<table>';
  foreach (
$form as $key => $value) {
   
$tmp = drupal_render($form[$key]);
   
$tmp = preg_replace('|</label>|i', '</label></td><td>', $tmp, 1);
   
$content .= '<tr><td>'.$tmp.'</td></tr>';
  }
 
$content .= '</table>';
  return
$content;
}
?>

------------------------------------------------
Comitto s.c.
http://www.comitto.eu/

 
 

Drupal is a registered trademark of Dries Buytaert.