Elements

If you are familiar with the Drupal forms API you know the concept of form elements as the basic building blocks of any form. Drupal provides several types of elements, some rather straightforward (#type textfield), some more advanced (#type password_confirm).

It is also possible to define custom form elements that enable you to implement complex widgets with ease.

At the moment, the focus of Elements is the tableselect widget. It provides a clean, easy way to create tables with one checkbox per row, multi-row selection and a select all checkbox, without making your code a complicated mess.

Example scaffolding

You can use the following code to create an example.module which you can use to experiment with the examples in this guide.

// example.module
function example_menu($maycache) {
  if ($maycache) {
    $items[] = array(
      'path' => 'scratch/elements',
      'access' => user_access('administer site configuration'),
      'type' => MENU_NORMAL_ITEM,
      'title' => t('Elements'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array('example_elements_form'),
    );
    return $items;
  }
}
; example.info
name = "Example"
description = "Quick scratch module."

Comboselect element

The comboselect element has not yet been included in Elements. You can follow its development at #268424.

The comboselect written by John Morahan gives you a select type element with an 'Other' option. When the user chooses this option; a textfield appears.

Create a simple comboselect element

function example_elements_form() {
$form = array();

$options = array(
'one' => t('First Option'),
'two' => t('Second Option'),
);

$form['choice'] = array(
'#type' => 'comboselect',
'#title' => t('Example'),
'#default_options' => $options,
);

$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
);

return $form;
}


Change the 'Other' option

AttachmentSize
comboselect_other_wording.JPG15.45 KB
function example_elements_form() {
$form = array();

$options = array(
'one' => t('First Option'),
'two' => t('Second Option'),
);

$form['test'] = array(
'#type' => 'comboselect',
'#title' => t('Example'),
'#required' => TRUE,
'#default_options' => $options,
'#other' => t('None of the above, but'),
);

$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
);

return $form;
}

Tableselect element

The form element tableselect provides a clean, easy way to create tables with one checkbox per row, multi-row selection and a select all checkbox, without making your code a complicated mess:

Update: This book is about the tableselect element provided by the Elements module for Drupal 5 and 6. See A new form element in Drupal core for a HOWTO on the new Drupal 7 form element.

A simple table

The basic properties of the tableselect element are #header which accepts an array of key => value pairs to generate the header from and #options, which receives an array of rows.

The basic structure looks like the following:

$header = array(
'field1' => 'Title of field 1',
'field2' => 'Title of field 2',
);

$options['some_unique_id'] = array(
'field1' => 'Value of field 1',
'field2' => 'Value of field 2',
);

The tableselect element relies on the keys to match columns with the appropriate header. The element will behave like the #checkboxes type. You'll get an array of values in your submit function, with the checked ones set to nonzero so you can array_filter them to get the checked rows.

function example_elements_form() {
$form = array();

$header = array(
'title' => t('Title'),
'author' => t('Author'),
);

$query = "SELECT n.nid, n.title, u.name FROM {node} n INNER JOIN {users} u ON n.uid = u.uid";
$result = pager_query(db_rewrite_sql($query));

while($partial_node = db_fetch_object($result)) {
$options[$partial_node->nid] = array(
'title' => check_plain($partial_node->title),
'author' => check_plain($partial_node->name),
);
}

if (!empty($options)) {
$form['nodes'] = array(
'#type' => 'tableselect',
'#header' => $header,
'#options' => $options,
);

$form['pager'] = array('#value' => theme('pager'));

$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
);

}
return $form;
}

Which results in:

Example table

Support for sortable tables

The tableselect element supports use with tablesort_sql. Simply modify the header to the format described in theme_table.

function example_elements_form() {
$form = array();

$header = array(
'title' => array('field' => 'n.title', 'data' => t('Title')),
'author' => array('field' => 'u.name', 'data' => t('Author')),
);

$query = "SELECT n.nid, n.title, u.name FROM {node} n INNER JOIN {users} u ON n.uid = u.uid". tablesort_sql($header);

$result = pager_query(db_rewrite_sql($query));

while($partial_node = db_fetch_object($result)) {
$options[$partial_node->nid] = array(
'title' => check_plain($partial_node->title),
'author' => theme('username', $partial_node),
);
}

if (!empty($options)) {
$form['nodes'] = array(
'#type' => 'tableselect',
'#header' => $header,
'#options' => $options,
);

$form['pager'] = array('#value' => theme('pager'));

$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
);

}

return $form;
}

Properties

#header
The table header, an array of field_key => title pairs or the format described for theme_table.
#options
The data displayed in the table. Nested array of id => array pairs where the array is an array of field_key => value pairs.
#multiple
Determines whether multiple values can be selected. Displays checkboxes when TRUE, radios when FALSE.
Default: TRUE
#advanced_select
Whether to provide advanced selection behaviour (SELECT ALL checkbox, SHIFT-select).
Default: TRUE - when #multiple is TRUE.
When #multiple is FALSE, always FALSE.
#default_value
Provide an array of id => x pairs for the ids that should be selected by default when #multiple is TRUE.
Provide the id as a scalar for the id that should be selected by default when #multiple is FALSE.