Heine

  • home
  • drupal
  • drupal core commits
  • about
Home › Drupal

A new form element in Drupal core

Heine — Wed, 28/01/2009 - 09:48

With Commit #167487, a new form element has been added to Drupal core (7.x) to provide an alternative means of selecting items. Now, next to 'select' (combobox, list), checkboxes and radios, core carries the 'tableselect' element. This element allows developers to easily create tables with selectable rows. Ideal for those situations where you have to provide a lot of data on the items to the user.

In line with the 'select' type, it has support for the #multiple property, allowing multiple or single item selection. When set to allow multiple item selection, the element automatically enables "Select all" and SHIFT-select functionality. This can optionally be disabled by setting the #js_select property to FALSE.

Sortable tables are easy as well; the element works seamlessly with tablesort_* functions.

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
#js_select
Whether to provide advanced selection behaviour (SELECT ALL checkbox, SHIFT-select).
Default: TRUE - when #multiple is TRUE.
When #multiple is FALSE, always FALSE.
#empty
Text to display over the full width of the table should #options be an empty array.
#default_value
#multiple TRUE - as checkboxes - provide an array of id => x pairs for the ids that should be selected by default when #multiple is TRUE.
#multiple FALSE - as radios - provide the id as a scalar for the id that should be selected by default when #multiple is FALSE.

Usage examples

Note that the code examples below contain a few 6.x constructs (db_query, db_rewrite_sql). The point is how the form element behaves.

The most important properties are #header and #options, on which the whole element functionality hinges. Both #header and #options accept keyed arrays. An item in the #header array has a significant key which is used by the element to match header and item columns later. #options accepts an array of arrays that is keyed by unique ids of the selectable items. The array value contains the values of the columns and has keys matching the #header array keys. An example should make this clearer:

$header = array(
  'column_1' => 'Title of column 1',
  'column_2' => 'Title of column 2',
);

$options['unique_id_item_1'] = array(
  'column_1' => 'Value of column 1, item 1',
  'column_2' => 'Value of column 2, item 1',
);

$options['unique_id_item_2'] = array(
  'column_1' => 'Value of column 1, item 2',
  'column_2' => 'Value of column 2, item 2',
);

Important: Column values are HTML; any plaintext must be escaped with check_plain.

A simple example

The following example creates the simple table you saw above.

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));

  $options = array();

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

  $form['nodes'] = array(
    '#type' => 'tableselect',
    '#header' => $header,
    '#options' => $options,
    // Should $options be array(), this will get displayed:
    '#empty' => t('No items available'),
  );

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

  return $form;
}

#default_value and #multiple

The value of $form_state['values']['nodes'] follows the format of the checkboxes type. By setting #multiple to FALSE, the checkboxes will be replaced by radio buttons. In that case, $form_state['values]['nodes'] follows the format of the radios type. Not just the behaviour of form values follows these elements, #default_value does so as well:

// When
$options = array(
  'one' => array(//...),
  'two' => array(//...),
  'three' => array(//...),
);

When #multiple is TRUE and row one is selected, $form_state['values']['nodes'] will be

array(
 'one' => 'one',
 'two' => 0
 'three' => 0,
)

When #multiple is FALSE and row one is selected, $form_state['values']['nodes'] will be

'one'

A sortable table

Instead of a simple title, #header values can also take a more complicated array in the format described for theme_table to support sortable tables.

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

  // Note the tablesort_sql($header).
  $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));

  $options = array();

  while($partial_node = db_fetch_object($result)) {
    $options[$partial_node->nid] = array(
      'title' => check_plain($partial_node->title),
      'author' => check_plain($partial_node->name),
    );
  }
 
  $form['nodes'] = array(
    '#type' => 'tableselect',
    '#header' => $header,
    '#options' => $options,
    '#empty' => t('No items available'),
  );

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

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

  return $form;
}

Thanks to moshe, chx and wimleers for input, noahb for lots of HEAD whitespace chasing rerolls and webchick for a review I could do something with.

Average: 4.9 (16 votes)
  • Drupal
  • FAPI
  • Planet Drupal

cool

rapsli (not verified) — Wed, 28/01/2009 - 11:45

awesome... is this already in a stable drupal version?

  • reply

It is in the 7.x development

Heine — Wed, 28/01/2009 - 12:38

It is in the 7.x development version. If you want to use the element in other versions of Drupal, use the Elements module.

  • reply

Woot

eigentor (not verified) — Wed, 28/01/2009 - 13:15

Rocks like Hell. :)))
So it will be also available for Permissions Page? Or rather not due to inherent danger of unwillingly enable too many rights?

  • reply

Does the Elements module in Drupal 6.0 work?

Marximus (not verified) — Tue, 24/03/2009 - 22:31

I can't see to get it to put the checkbox(es) or radios in the first column. I've traced this to a line of code in theme_tableselect...

$row[] = drupal_render($element[$key]);

... which (it appears) is supposed to cause _elements_expand_tableselect to be invoked... but it doesn't. I don't see how it can... as $element[$key] is undefined... assuming you follow the example of how to assemble the form.

Could be there is something simple missing from the read-me?

  • reply

The tableselect element from

Heine — Wed, 25/03/2009 - 18:16

The tableselect element from Elements for Drupal 6 certainly works. _elements_expand_table select is called during form processing, so I'm pretty sure you are not correctly building the form (via drupal_get_form('form_builder').

You may want to post code. See also http://heine.familiedeelstra.com/coding-help-tips.

  • reply

Yup, you are correct... I was using it incorrectly...

Marximus (not verified) — Wed, 25/03/2009 - 21:03

Sorry about the fuss. Never meant to cast Elements in a bad light... just wanted confirmation that it worked... assuming I used it correctly.

A long story short... I build a table (of book titles) using the table and pager themes... wanted to give the user the option to select table rows ("hide this from me", "I own this one"). So the paradigm was purely "output"... and my hook_menu had no need to call "drupal_get_form" as the page wasn't a form. I thought I could fake my way through this with "drupal_render"... but apparently not. So I've modified the menu hook and now the form displays correctly... with checkboxes displayed. (Now to get it to work with the pager theme and JS... ahhh the challenges).

As the Elements is seeking a maintainer, I felt it prudent to simply ask "does it work?" The code checked in for Drupal v7.0 is somewhat changed... so who knows? Sorry to have wasted your time.

Thanks,

Mark

PS. My posts don't really contribute to the meat of your thread here... I've no qualms if you delete them.

  • reply

Nice work Heine! This patch

Anonymous (not verified) — Wed, 28/01/2009 - 20:37

Nice work Heine! This patch is in due to your skill and guidance...

  • reply

Awesome news, Heine. Look

Ryan (not verified) — Wed, 28/01/2009 - 20:43

Awesome news, Heine. Look forward to putting this to good use!

  • reply

Great

Sven Decabooter (not verified) — Wed, 28/01/2009 - 22:11

Great feature!
This will make a lot of administration pages so much easier.

  • reply

Great job!

Wim Leers (not verified) — Wed, 28/01/2009 - 22:35

Thanks for your efforts Heine! I know it took quite some time & effort :)

  • reply

Awesome work!

Dave Reid (not verified) — Wed, 28/01/2009 - 22:45

You did a great job on this issue Heine! Congrats!

  • reply

Good stuff! What about extra columns in the <tbody> section?

Kent R (not verified) — Thu, 26/03/2009 - 05:16

I want to emulate a form like on admin/build/contact, where there are two columns under the 'Operations' header.

I found I can do this by embedding closing and opening tags for <td> into the value for the 'operations' key like below, but I'm wondering if there's a cleaner way (something more along the lines of how rows are built for input to theme_table() ):

$options[$item->id] = array(
        'title'         =>
                l( $item->title, 'admin/my_module/edit/' . $item->id, array('query' => $destination) ) ,

        'id'            =>
                $item->id,

        'operations'    =>
                l( t('edit'), 'admin/my_module/edit/' . $item->id, array('query' => $destination) ) .
                '</td><td>' .
                l( t('delete'), 'admin/my_module/delete' . $item->id, array('query' => $destination) ),
);

  • reply

Very nice tutorial, But how

Lasters s (not verified) — Fri, 30/10/2009 - 12:26

Very nice tutorial, But how do I know which values are selected?

  • reply

Depending on #multiple, just like checkboxes / radios

Heine — Fri, 30/10/2009 - 13:31

The table select element works like checkboxes or radios (depending on #multiple).

Suppose we have the following form:

  $header = array(
    'column_1' => 'Title of column 1',
    'column_2' => 'Title of column 2',
  );

  $options['unique_id_item_1'] = array(
    'column_1' => 'Value of column 1, item 1',
    'column_2' => 'Value of column 2, item 1',
  );

  $options['unique_id_item_2'] = array(
    'column_1' => 'Value of column 1, item 2',
    'column_2' => 'Value of column 2, item 2',
  );

  $form['example'] = array(
    '#type' => 'tableselect',
    '#header' => $header,
    '#options' => $options,
    '#multiple' => // TRUE or FALSE
    // Should $options be array(), this will get displayed:
    '#empty' => t('No items available'),
  );

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

When #multiple is FALSE and you select unique_id_item_1, $form_state['values']['example'] will be 'unique_id_item_1'.

When #multiple is TRUE, $form_state['values']['example'] will be :

array
(
    [unique_id_item_1] => unique_id_item_1
    [unique_id_item_2] => 0
)

You can filter this array with array_filter to get just the selected items.

  • reply

Drupal Module SELECT Control

Anirudh (not verified) — Tue, 01/12/2009 - 11:20

How do i get value selected in select control after submiting form in module...

$gender = $form_state['values']['gender'];

this is giving me whole list, i want only selected value....!!!!

Thanx in adv.

  • reply

array_filter

Heine — Thu, 03/12/2009 - 08:41

If you are using the tableselect control with #multiple set to TRUE you get as value an array with
selected items (value == key) and nonselected items (value 0):

array(
 'one' => 'one',
 'two' => 0
 'three' => 0,
)

You can remove the nonselected items with $filtered = array_filter($form_state['values']['foo']).

Calling array_filter on the previous example array would result in the following array:

array(
  'one' => 'one',
)

  • reply

make tableselect with expanded row

chenop (not verified) — Sat, 30/01/2010 - 23:41

Hi,

I'm using the elements module in my site.

I want to make the rows of the table expanded, which mean that when a user will click the row an extra info will be shown regarding the node that was clicked.
A second click will collapse the row.

I guess this feature should be done somehow with Javascript.

Anyone have an idea how should i do it?

  • reply

Post new comment

I reserve the right to edit any comment submitted to the site. If your comment contains flaming, advertisements, or simply too many spelling errors (leet speak), it may never appear.
The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <blockquote>
  • Lines and paragraphs break automatically.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <as>, <as3>, <csharp>, <diff>, <drupal5>, <drupal6>, <html>, <js>, <mysql>, <php>, <phpbrief>, <python>, <sql>, <plain>, <xml>. Beside the tag style "<foo>" it is also possible to use "[foo]". PHP source code can also be enclosed in <?php ... ?> or <% ... %>.

More information about formatting options

Recent posts

  • The Joomlafication of the Dutch-speaking community
  • Upgraded from 6.14 to 6.15, but Drupal still thinks it's 6.14?
  • Google Friendconnect Drupal module not recommended (yet)
  • The OpenID 2.0 Compliance Crusade - Part I
  • Using <embed> for XSS
more

Security reviews

  • Afraid custom code makes your site vulnerable?
  • You don't really trust that module you just downloaded from Drupal.org?

Sleep better after a security review.

Tags

Captcha CSRF DOH! Drupal embed Input Format modx OpenID Performance Planet Drupal Security Varnish
more tags
  • home
  • drupal
  • drupal core commits
  • about

Copyright © 2010 by Heine Deelstra. All rights reserved.