1

I created a custom module that contains a form with select element I tried to disable the first option like this, but failed to get it work

'#options' => $terms,
                '#empty_option' => '- Select category -',
                '#empty_value' => 'none',
                '#disabled_values' => array('none'),

How could this be achieved without removing the option?

5 Answers 5

0

There is a contrib module that can help: Form Options Attributes

This module adds the ability to specify attributes for individual options on Drupal Form API elements of the types: select, checkboxes, and radios.

Also Jaime Calvo's answer about writing:

['#options']['my disabled option'] = [];

Doesn't really create a disabled option, but an empty optgroup.

3

Drupal by default doesn't allow for this, so you'll need to do two things:

  1. Override theme_select()
  2. Create your own callback the create the options
  3. Change the way you define your select options in your form definition

Overriding theme_select():

function THEME_select($variables) {
  $element = $variables['element'];
  element_set_attributes($element, array('id', 'name', 'size'));
  _form_set_class($element, array('form-select'));

  return '<select' . drupal_attributes($element['#attributes']) . '>' . custom_form_select_options($element) . '</select>';
}

Create your own callback the create the options:

function custom_form_select_options($element, $choices = NULL) {
  if (!isset($choices)) {
    $choices = $element['#options'];
  }
  // array_key_exists() accommodates the rare event where $element['#value'] is NULL.
  // isset() fails in this situation.
  $value_valid = isset($element['#value']) || array_key_exists('#value', $element);
  $value_is_array = $value_valid && is_array($element['#value']);
  $options = '';
  foreach ($choices as $key => $choice) {
    if (is_array($choice) && !isset($choice['data'])) {
      $options .= '<optgroup label="' . check_plain($key) . '">';
      $options .= form_select_options($element, $choice);
      $options .= '</optgroup>';
    }
    elseif (is_object($choice)) {
      $options .= form_select_options($element, $choice->option);
    }
    else {
      $key = (string) $key;
      if ($value_valid && (!$value_is_array && (string) $element['#value'] === $key || ($value_is_array && in_array($key, $element['#value'])))) {
        $selected = ' selected="selected"';
      }
      else {
        $selected = '';
      }
      $options .= '<option value="' . check_plain($key) . '"' . $selected;
      if(is_array($choice) && isset($choice['disabled']) && $choice['disabled'])
      {
          $options .= ' disabled';
      }
      $choice = is_array($choice) && isset($choice['data']) ? $choice['data'] : $choice;
      $options .= '>' . check_plain($choice) . '</option>';
    }
  }
  return $options;
}

Change the way you define your select options in your form definition. Turn the option into an array with two keys:

  1. data: The display value of the element
  2. disabled: A boolean indicating whether to disable the element

Example:

$form['select'] = array(
  '#title' => t('Pick something'),
  '#type' => 'select',
  '#options' => array(
    'yes' => array('data' => t('Yes'), 'disabled' => TRUE),
    'no' => t('No'),
  ),
);
3
  • The function THEME_select() and THEME_form_select_options() override by theme. That mean if you write a module, you need override theme too. I think, you can define method process of element select. Same with my problem is here.
    – MrD
    Feb 16, 2017 at 2:36
  • THEME_form_select_options() was named incorrectly. I have updated my code.
    – Jaypan
    Feb 16, 2017 at 2:40
  • Your way is correctly. I just note, if you just write in your module. You can write once use everywhere(when you change theme, you don't need copy and override function THEME_select() ).
    – MrD
    Feb 16, 2017 at 2:47
0

I prefer in this case use a single line of jQuery.

$("select option:first-child").attr("disabled", "true");

It adds the disabled attribute :

<option value="disabled_options" disabled="disabled">-- choice : --</option>

I would have preferred to do it with formApi but I think this is too much code for a basic thing.

0

I took Sébastien Gicquel answer and tweaked it a little, so you can define disabled options when building form.

It is for Drupal 10 but I think it is so simple that should work on other Drupal versions as well.

In JS file (I created small library mymodule\forms to customize forms) create code to disable certain options.

$(".select-options-disabled").each(function(){
  let selectNode = $(this);
  let optionsIdxs = selectNode.data('options-disabled').split(",");
  $.each(optionsIdxs, function(_i, idx){
    selectNode.find('option:nth-child(' + idx + ')').attr("disabled", "true");
  });
});

Then in any buildForm function when you want to create select with disabled options just add two attributes to it. Class .select-options-disabled, and data-options-disabled as comma seperated list of options to disable in given select. For example:

$form['my_options'] = array(
  '#type'          => 'select',
  '#options'       => $options,
  '#attributes' => [
    'class' => ['select-options-disabled'],
    'data-options-disabled' => '1,3',
  ],
);

Remember to add your JS file in my case it is my library

$form['#attached']['library'][] = 'mymodule/forms';

Also keep in mind that CSS nth-child selector starts from 1, not 0 therefore to disable first option in select add "1" not "0" :)

Still I wish there would be better option to do this, if there is please add comment here.

-1

If you just set an empty array as value the option will be disabled.

['#options']['my disabled option'] = [];

this option will get the name, 'my disabled option' and will be disabled.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.