Adding attribute to option element using forms api : drupal 7

19,624

Solution 1

I'm afraid you're going to have to dig quite far down to do this, the #options array is flattened in form_select_options() and it doesn't currently include any way of adding attributes. This is the code:

$options .= '<option value="' . check_plain($key) . '"' . $selected . '>' . check_plain($choice) . '</option>';

As you can see there's simply no scope for attributes in there. You will be able to override this though, but it will involve implementing your own version of theme_select() and your own FAPI property.

I haven't got time to flesh the entire thing out but in your theme file you would be doing something like this:

function MYTHEME_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']) . '>' . MYTHEME_form_select_options($element) . '</select>';
}


function MYTHEME_form_select_options($element) {
  // Build up your own version of form_select_options here
  // that takes into account your extra attribute needs.
  // This will probably involve inspecting your custom FAPI property,
  // which we'll call #extra_option_attributes
}

Refer to form_select_options for constructing MYTHEME_form_select_options

And your code in the form would be something like:

$form['select'] = array(
  '#type' => 'select',
  '#options' => array(1 => 'One', 2 => 'Two'),
  '#extra_option_attributes' => array(
    1 => array('title' => 'Test title'), // Attributes for option with key "1",
    2 => array('title' => 'Test title'), // Attributes for option with key "2",
  ) 
);

In MYTHEME_form_select_options() you can then inspect the element's #extra_option_attributes key (if one exists) to see if you need to physically add any more attributes in the HTML you create.

Hope that helps, I know it seems like a crazily long-winded way of doing what you need to but as far as I know it's the only way.

Solution 2

Tested

Try:

$form["tid"][1]['#attributes'] = array('title' => t('nooo chatter'));

instead of:

$form["tid"]['#options'][1]['#attributes'] = array('title' => t('nooo chatter'));

It is possible to add arbitrary attributes to elements this way. I discovered this after performing some tests based on this answer.

Also mentioned here and here.

Share:
19,624
Vishal Khialani
Author by

Vishal Khialani

I am a web developer and I work on drupal most of the time. I have travelled the world and worked in china, Taiwan and Indonesia for 7 years. Please feel free to connect with me at my BLOG

Updated on June 27, 2022

Comments

  • Vishal Khialani
    Vishal Khialani almost 2 years

    I want to add title="icons/icon_cart.gif" for each of the below options in my select list which is rendered using views.

    After trying and reading many articles I can't seem to find the way to add this html into my form.

    Below is my code.

    function customchatter_form_alter(&$form, &$form_state, $form_id) {
    
    $form["tid"]["#options"][1]=t("nooo chatter");
    // this works to change the label of the option but how do I add title="icons/icon-  
    cart.gif" ?
    
    }
    

    My html code:

    <select id="edit-tid" name="tid" class="form-select">
    <option value="All">- Any -</option>
    <option value="1">nooo chatter</option>
    <option value="2">Complaints Complaints</option>
    <option value="3">Gear &amp; Gadgets</option>
    </select>
    

    Cheers, Vishal

    UPDATE I tried to update the code as per Clive's advice but the values are still not coming up right. Below is my story.

    So below is the html output I am able to achieve but the title always seems to be the number 1.

    <select id="edit-select" class="form-select" name="select">
    <option value="1" title="1">One</option>
    <option value="2" title="1">Two</option>
    </select>
    

    As you can see title is there but the value is wrong. Below is my form and the functions which I wrote.

    My form:

    $form['select'] = array(
    '#type' => 'select',
    '#options' => array(1 => 'One', 2 => 'Two'),
    '#title' => array(1 => 'One', 2 => 'Two') 
    // I tried many combinations but nothing seems to work.
    );
    

    My Theme functions.

    function kt_vusers_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']) . '>' .    
    kt_vusers_form_select_options($element) . '</select>';
    }
    
    
    function kt_vusers_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);
    
    
    // @vishal  so there I have declared the variable to accept the values.
    $vtitle = isset($element['#title']) || array_key_exists('#title', $element);
    
    
    $value_is_array = $value_valid && is_array($element['#value']);
    $options = '';
    foreach ($choices as $key => $choice) {
    if (is_array($choice)) {
      $options .= '<optgroup label="' . $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 = '';
      }
    
     // @vishal this is where the variable is being used.
    
     $options .= '<option title="'.$vtitle.'" value="' . check_plain($key) . '"' . $selected . 
     '>' . check_plain($choice) . '</option>';
    }
    }
    return $options;
    }
    

    below is the correct code for the last theme function

    function kt_vusers_form_select_options($element, $choices = NULL, $vtitles=NULL) {
    // Build up your own version of form_select_options here
    // that takes into account your extra attribute needs.
    // This will probably involve inspecting your custom FAPI property,
    // which we'll call #extra_option_attributes
    
    if (!isset($choices)) {
    $choices = $element['#options'];
    $vtitles = array();
    $vtitles = $element['#title'];
    }
    // 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 = '';
    
    //  print_r($vtitles);
    

    while ( (list($key, $choice) = each($choices)) && (list($keytwo, $vtitle) = each($vtitles)) ) { // printf("%s => %s, %s => %s \n", $key1, $value1, $key2, $value2);

     if (is_array($choice)) {
        $options .= '<optgroup label="' . $key . '">';
        $options .= kt_vusers_form_select_options($element, $choice);
        $i++;
        // $options .= form_select_options($element, $vtitle);
        $options .= '</optgroup>';
        } // end if if is_array
    
     elseif(is_object($choice)) {
      $options .= form_select_options($element, $choice->option);
      } // end of else if
    
    
    
    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 title="'.$vtitle.'" value="' . check_plain($key) . '"' . 
      $selected . '>' . check_plain($choice) . '</option>';
    
    
     }
    
     $options .= '<option value="'. check_plain($key) .'" title="' . $vtitle . '"' . $selected 
     .'>'. check_plain($choice) .'</option>';
    
    
    
     } // end of choice
    
    
    
    return $options;
    
    
    } // end of function
    
  • SpaceBeers
    SpaceBeers about 12 years
    You win this round @Clive. You win this round. +1 for effort.
  • Vishal Khialani
    Vishal Khialani about 12 years
    clive I have updated the post I am able to get the title there in the html but the value always seem to be one.
  • Sharique
    Sharique almost 12 years
    In my case I'm getting error "Undefined index: render element in theme() " on $element = $variables['element']; in theme.inc file.
  • Matt Fletcher
    Matt Fletcher about 11 years
    +1 because I don't think having negative rep on an answer that was in good faith is fair!
  • OhkaBaka
    OhkaBaka over 10 years
    Damned depressing... theme solutions always feel dirty. Oh well.
  • Druvision
    Druvision over 10 years
    Thanks @Clive for the inspiration. Here is how I did the same thing for checkboxes: drupal.stackexchange.com/questions/89226/…
  • Collins
    Collins over 7 years
    This didnt work for me, it added them outside of the options array, so nothing rendered for each element.