You are here

class Tableselect in Drupal 10

Same name and namespace in other branches
  1. 8 core/lib/Drupal/Core/Render/Element/Tableselect.php \Drupal\Core\Render\Element\Tableselect
  2. 9 core/lib/Drupal/Core/Render/Element/Tableselect.php \Drupal\Core\Render\Element\Tableselect

Provides a form element for a table with radios or checkboxes in left column.

Properties:

  • #header: An array of table header labels.
  • #options: An associative array where each key is the value returned when a user selects the radio button or checkbox, and each value is the row of table data.
  • #empty: The message to display if table does not have any options.
  • #multiple: Set to FALSE to render the table with radios instead checkboxes.
  • #js_select: Set to FALSE if you don't want the select all checkbox added to the header.

Other properties of the \Drupal\Core\Render\Element\Table element are also available.

Usage example:

$header = [
  'color' => $this
    ->t('Color'),
  'shape' => $this
    ->t('Shape'),
];
$options = [
  1 => [
    'color' => 'Red',
    'shape' => 'Triangle',
  ],
  2 => [
    'color' => 'Green',
    'shape' => 'Square',
  ],
  3 => [
    'color' => 'Blue',
    'shape' => 'Hexagon',
  ],
];
$form['table'] = array(
  '#type' => 'tableselect',
  '#header' => $header,
  '#options' => $options,
  '#empty' => $this
    ->t('No shapes found'),
);

See https://www.drupal.org/node/945102 for a full explanation.

Plugin annotation

@FormElement("tableselect");

Hierarchy

Expanded class hierarchy of Tableselect

See also

\Drupal\Core\Render\Element\Table

1 file declares its use of Tableselect
TableSelectTest.php in core/tests/Drupal/Tests/Core/Render/Element/TableSelectTest.php
9 #type uses of Tableselect
AddHandler::buildForm in core/modules/views_ui/src/Form/Ajax/AddHandler.php
CommentAdminOverview::buildForm in core/modules/comment/src/Form/CommentAdminOverview.php
Form constructor for the comment overview administration form.
ContentModerationConfigureEntityTypesForm::buildForm in core/modules/content_moderation/src/Form/ContentModerationConfigureEntityTypesForm.php
Form constructor.
DatabaseTestForm::buildForm in core/modules/system/tests/modules/database_test/src/Form/DatabaseTestForm.php
Form constructor.
ElementsTableSelectTest::testMultipleFalseOptionchecker in core/modules/system/tests/src/Functional/Form/ElementsTableSelectTest.php
Tests the whether the option checker gives an error on invalid tableselect values for radios.

... See full list

File

core/lib/Drupal/Core/Render/Element/Tableselect.php, line 53

Namespace

Drupal\Core\Render\Element
View source
class Tableselect extends Table {

  /**
   * {@inheritdoc}
   */
  public function getInfo() {
    $class = static::class;
    return [
      '#input' => TRUE,
      '#js_select' => TRUE,
      '#multiple' => TRUE,
      '#responsive' => TRUE,
      '#sticky' => FALSE,
      '#pre_render' => [
        [
          $class,
          'preRenderTable',
        ],
        [
          $class,
          'preRenderTableselect',
        ],
      ],
      '#process' => [
        [
          $class,
          'processTableselect',
        ],
      ],
      '#options' => [],
      '#empty' => '',
      '#theme' => 'table__tableselect',
    ];
  }

  /**
   * {@inheritdoc}
   */
  public static function valueCallback(&$element, $input, FormStateInterface $form_state) {

    // If $element['#multiple'] == FALSE, then radio buttons are displayed and
    // the default value handling is used.
    if (isset($element['#multiple']) && $element['#multiple']) {

      // Checkboxes are being displayed with the default value coming from the
      // keys of the #default_value property. This differs from the checkboxes
      // element which uses the array values.
      if ($input === FALSE) {
        $value = [];
        $element += [
          '#default_value' => [],
        ];
        foreach ($element['#default_value'] as $key => $flag) {
          if ($flag) {
            $value[$key] = $key;
          }
        }
        return $value;
      }
      else {
        return is_array($input) ? array_combine($input, $input) : [];
      }
    }
  }

  /**
   * Prepares a 'tableselect' #type element for rendering.
   *
   * Adds a column of radio buttons or checkboxes for each row of a table.
   *
   * @param array $element
   *   An associative array containing the properties and children of
   *   the tableselect element. Properties used: #header, #options, #empty,
   *   and #js_select. The #options property is an array of selection options;
   *   each array element of #options is an array of properties. These
   *   properties can include #attributes, which is added to the
   *   table row's HTML attributes; see table.html.twig. An example of per-row
   *   options:
   *   @code
   *     $options = array(
   *       array(
   *         'title' => $this->t('How to Learn Drupal'),
   *         'content_type' => $this->t('Article'),
   *         'status' => 'published',
   *         '#attributes' => array('class' => array('article-row')),
   *       ),
   *       array(
   *         'title' => $this->t('Privacy Policy'),
   *         'content_type' => $this->t('Page'),
   *         'status' => 'published',
   *         '#attributes' => array('class' => array('page-row')),
   *       ),
   *     );
   *     $header = array(
   *       'title' => $this->t('Title'),
   *       'content_type' => $this->t('Content type'),
   *       'status' => $this->t('Status'),
   *     );
   *     $form['table'] = array(
   *       '#type' => 'tableselect',
   *       '#header' => $header,
   *       '#options' => $options,
   *       '#empty' => $this->t('No content available.'),
   *     );
   *   @endcode
   *
   * @return array
   *   The processed element.
   */
  public static function preRenderTableselect($element) {
    $rows = [];
    $header = $element['#header'];
    if (!empty($element['#options'])) {

      // Generate a table row for each selectable item in #options.
      foreach (Element::children($element) as $key) {
        $row = [];
        $row['data'] = [];
        if (isset($element['#options'][$key]['#attributes'])) {
          $row += $element['#options'][$key]['#attributes'];
        }

        // Render the checkbox / radio element.
        $row['data'][] = \Drupal::service('renderer')
          ->render($element[$key]);

        // As table.html.twig only maps header and row columns by order, create
        // the correct order by iterating over the header fields.
        foreach ($element['#header'] as $fieldname => $title) {

          // A row cell can span over multiple headers, which means less row
          // cells than headers could be present.
          if (isset($element['#options'][$key][$fieldname])) {

            // A header can span over multiple cells and in this case the cells
            // are passed in an array. The order of this array determines the
            // order in which they are added.
            if (is_array($element['#options'][$key][$fieldname]) && !isset($element['#options'][$key][$fieldname]['data'])) {
              foreach ($element['#options'][$key][$fieldname] as $cell) {
                $row['data'][] = $cell;
              }
            }
            else {
              $row['data'][] = $element['#options'][$key][$fieldname];
            }
          }
        }
        $rows[] = $row;
      }

      // Add an empty header or a "Select all" checkbox to provide room for the
      // checkboxes/radios in the first table column.
      if ($element['#js_select']) {

        // Add a "Select all" checkbox.
        $element['#attached']['library'][] = 'core/drupal.tableselect';
        array_unshift($header, [
          'class' => [
            'select-all',
          ],
        ]);
      }
      else {

        // Add an empty header when radio buttons are displayed or a "Select all"
        // checkbox is not desired.
        array_unshift($header, '');
      }
    }
    $element['#header'] = $header;
    $element['#rows'] = $rows;
    return $element;
  }

  /**
   * Creates checkbox or radio elements to populate a tableselect table.
   *
   * @param array $element
   *   An associative array containing the properties and children of the
   *   tableselect element.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   * @param array $complete_form
   *   The complete form structure.
   *
   * @return array
   *   The processed element.
   */
  public static function processTableselect(&$element, FormStateInterface $form_state, &$complete_form) {
    if ($element['#multiple']) {
      $value = is_array($element['#value']) ? $element['#value'] : [];
    }
    else {

      // Advanced selection behavior makes no sense for radios.
      $element['#js_select'] = FALSE;
    }
    $element['#tree'] = TRUE;
    if (count($element['#options']) > 0) {
      if (!isset($element['#default_value']) || $element['#default_value'] === 0) {
        $element['#default_value'] = [];
      }

      // Create a checkbox or radio for each item in #options in such a way that
      // the value of the tableselect element behaves as if it had been of type
      // checkboxes or radios.
      foreach ($element['#options'] as $key => $choice) {

        // Do not overwrite manually created children.
        if (!isset($element[$key])) {
          if ($element['#multiple']) {
            $title = '';
            if (isset($element['#options'][$key]['title']) && is_array($element['#options'][$key]['title'])) {
              if (!empty($element['#options'][$key]['title']['data']['#title'])) {
                $title = new TranslatableMarkup('Update @title', [
                  '@title' => $element['#options'][$key]['title']['data']['#title'],
                ]);
              }
            }
            $element[$key] = [
              '#type' => 'checkbox',
              '#title' => $title,
              '#title_display' => 'invisible',
              '#return_value' => $key,
              '#default_value' => isset($value[$key]) ? $key : NULL,
              '#attributes' => $element['#attributes'],
              '#ajax' => $element['#ajax'] ?? NULL,
            ];
          }
          else {

            // Generate the parents as the autogenerator does, so we will have a
            // unique id for each radio button.
            $parents_for_id = array_merge($element['#parents'], [
              $key,
            ]);
            $element[$key] = [
              '#type' => 'radio',
              '#title' => '',
              '#return_value' => $key,
              '#default_value' => $element['#default_value'] == $key ? $key : NULL,
              '#attributes' => $element['#attributes'],
              '#parents' => $element['#parents'],
              '#id' => HtmlUtility::getUniqueId('edit-' . implode('-', $parents_for_id)),
              '#ajax' => $element['#ajax'] ?? NULL,
            ];
          }
          if (isset($element['#options'][$key]['#weight'])) {
            $element[$key]['#weight'] = $element['#options'][$key]['#weight'];
          }
        }
      }
    }
    else {
      $element['#value'] = [];
    }
    return $element;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DependencySerializationTrait::$_entityStorages protected property
DependencySerializationTrait::$_serviceIds protected property
DependencySerializationTrait::__sleep public function 2
DependencySerializationTrait::__wakeup public function 2
FormElement::processAutocomplete public static function Adds autocomplete functionality to elements.
FormElement::processPattern public static function #process callback for #pattern form element property.
FormElement::validatePattern public static function #element_validate callback for #pattern form element property.
MessengerTrait::$messenger protected property The messenger. 18
MessengerTrait::messenger public function Gets the messenger. 18
MessengerTrait::setMessenger public function Sets the messenger.
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition.
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function
PluginBase::getDerivativeId public function
PluginBase::getPluginDefinition public function 2
PluginBase::getPluginId public function
PluginBase::isConfigurable public function Determines if the plugin is configurable.
PluginBase::__construct public function Constructs a \Drupal\Component\Plugin\PluginBase object. 53
RenderElement::preRenderAjaxForm public static function Adds Ajax information about an element to communicate with JavaScript.
RenderElement::preRenderGroup public static function Adds members of this group as actual elements for rendering.
RenderElement::processAjaxForm public static function Form element processing handler for the #ajax form property. 1
RenderElement::processGroup public static function Arranges elements into groups.
RenderElement::setAttributes public static function Sets a form element's class attribute. Overrides ElementInterface::setAttributes
StringTranslationTrait::$stringTranslation protected property The string translation service. 3
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 1
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.
Table::preRenderTable public static function #pre_render callback to transform children of an element of #type 'table'.
Table::processTable public static function #process callback for #type 'table' to add tableselect support.
Table::validateTable public static function #element_validate callback for #type 'table'.
Tableselect::getInfo public function Returns the element properties for this element. Overrides Table::getInfo
Tableselect::preRenderTableselect public static function Prepares a 'tableselect' #type element for rendering.
Tableselect::processTableselect public static function Creates checkbox or radio elements to populate a tableselect table.
Tableselect::valueCallback public static function Determines how user input is mapped to an element's #value property. Overrides Table::valueCallback