Is it possible using FormAPI to assign attributes to a single radio button within a "radios" set? I've tried the following, inside a custom hook_form_alter function:

$form['field_smoking']['key']['#options']['I smoke daily.']['#attributes'] = array('class' => 'switch-smoker');

But it doesn't seem to be working. What am I missing?

Comments

mooffie’s picture

A 'radios' element gets expanded to individual 'radio' elements at some stage. The form_alter stage is too early and this expansion hasn't yet taken place. The theming stage, however, is late enough, so there you do have access to the individual 'radio' element. But there's a stage even earlier than the theming stage: #after_build. You can install a handler for this stage in form_alter:

function form_alter(...) {
  // $form['hobbies'] is the 'radios' element.
  $form['hobbies']['#after_build'][] = '_mymodule_highlight_origami', 
}

function _mymodule_highlight_origami($element) {
  // the 'origami' radio has been expanded by now
  $element['origami']['#attributes']['class'] = 'evil';
  return $element;
}
matt v.’s picture

mooffie,

Thanks a lot! I hadn't run across #after_build before. That was just what I needed.

bjacob’s picture

I've tried this method for adding additional attributes to the options of a select field. Here's what I did:

Output of $element (part):

Array
(
    [#tree] => 1
    [key] => Array
        (
            [#type] => select
            [#title] => Status
            [#options] => Array
                (
                    [] => 
                    [A] => A
                    [B] => B
                    [C] => C
                )
        )
)

My after_build function. I'm sure it's called.

function _custom_kit_option_elements($element) {
  $element['A']['#attributes'] = array('foo' => 'bar');

  return $element;
}

Somehow it's not working. Thanks for any help!

mooffie’s picture

I've tried this method for adding additional attributes to the options

You can't. Drupal doesn't support attributes for options.

(However, you can #theme the selectbox yourself to draw it entirely, then you'd be able to do whatever you want.)

Yes, it could be useful to be able to attach CSS classes to individual options, via FAPI, e.g. to color them differently. You should open a feature request.

bjacob’s picture

Thanks mooffie for your answer. Can you tell me which theme function is responsible for drawing selects / options?

IMHO IE is not able to interpret classes or anything else (like disable="disable"). In my case I've to provide a select box where some options are not available for selecting but have to be displayed. So I started with disabled. After I found out it's not working in IE I've found a JS snippet which does something like that:

<html>
<head>
<script>
function disableOption(dropdown) {
if (dropdown.options[dropdown.selectedIndex].state == 'disabled') {
  dropdown.selectedIndex = 0;
  alert('disabled');
}
}
</script>
</head>
<body>
<form >
<select name="select1" onChange="disableOption(this.form.select1);">
<option value="1" state="enabled">one</option>
<option value="2" state="enabled">two</option>
<option value="3" state="disabled"
style="background-color:silver">three</option>
<option value="4" state="disabled"
style="background-color:silver">four</option>
</select>
<input type="submit">
</form>
</body>
</html>

As you can see, I've to add for every single option a state value. Thanks again for your help.

mooffie’s picture

Can you tell me which theme function is responsible for drawing selects / options?

But that's only part of the story. I understand that you want to write some JS code that simulates disabled options. If I were you I'd do everything on the JS side --instead of maintaining two pieces of code.

IMHO IE is not able to interpret classes
[...]
I started with disabled. After I found out it's not working in IE [...]

But are you sure IE doesn't support 'class'? (if it supports 'style', it sure does support 'class') Because if it doesn't, you won't be able to paint the options in grey to give the impression they're disabled.

matt v.’s picture

If you're using Drupal 6, the Devel module provides a way to find what function is responsible for formatting a particular piece of content. For Drupal 5, there's a trick detailed here.

--
Drupal Theme Developer’s Cheat Sheet | 45 Screencasts to Get You Kicking Ass with Drupal

bjacob’s picture

Mmh, I don't know if I can theme it. There are two functions: function theme_select() and function form_select_options(). I thought I can only overwrite theme functions like theme_select(). Or am I wrong? I've tried to copy the form_select_options() function to my template.php and renamed the function to phptemplate_form_select_options() but nothing happened.

EDIT: I've found a solution in JavaScript (jquery):

<script type="text/javascript">
$(document).ready(function() {
  $('#edit-field-status-key option[@value="A"]').attr("state","disabled");
  $('#edit-field-status-key option[@value="B"]').attr("state","disabled");

  $('#edit-field-status-key').bind('change', function() {
    var state = $('#edit-field-status-key option:selected').attr('state');
    if (state == 'disabled') {
      $('#edit-field-status-key option:eq(0)').attr("selected","selected");
      alert('Your are not allowed to select this status.');
    }
  });
});
</script>
Cyclodex’s picture

Thanks a lot for this solution. That works great! My first time using #after_build :)

Sswater Shi’s picture

I tried, use '#after_build' is OK.

There another alternative way, I tested in drupal 7, post here for reference:


  $options = array(
    'a' => 'AAA',
    'b' => 'BBB',
  );

  $form['choose'] = array(
    '#type' => 'radios',
    '#options' => $options,
  );

  $form['choose']['a']['#attributes'] = array('attr1' => 'v1');
  $form['choose']['b']['#attributes'] = array('attr1' => 'v2');

meetanilchauhan’s picture

Drupal FAPI does not support this feature but we can add attributes to options by slightly modifying form.inc file.

You only need to change following line in form.inc file.

       $options .= '<option value="'. check_plain($key) .'"'. $selected .'>'. check_plain($choice) .'</option>'; 
       //line no. 1437 of form_select_options() in drupal 6.10 

with this

       $options .= '<option value="'. check_plain($key) .'"'. $selected . drupal_attributes($element['#options_attribute'][$key]) . '>'. check_plain($choice) .'</option>';
       //line no. 1437 of form_select_options() in drupal 6.10 

You can use like it.

        $shipping_methods = array('1' => 'Standard Two-Day ($17.00 Total Shipping Price)',
								'2' => 'Priority Overnight ($26.00 Total Shipping Price)',
								'3' => 'FedEx Next Day Delivery $23.95',
								'4' => 'FedEx Next Day Delivery $23.95');
								
	$shipping_method_options = array('1' => array('price' => '17.00', 'class' => 'one'),
								'2' => array('price' => '26.00', 'class' => 'two'),
								'3' => array('price' => '23.95', 'class' => 'three'),
								'4' => array('price' => '23.95', 'class' => 'four'));
	
	$form['default_shipping_method'] = array(
		'#title' => t('Shipping Method'),
		'#type' => 'select',
		'#options' => $shipping_methods,
		'#options_attribute' => $shipping_method_options,
		'#default_value' => variable_get('default_shipping_method', 0),
		'#description' => t('You can change your shipping method from here.'),
	);