Hi all,

I have the following form:

$form['some_options'] = array(
'#type' => 'radios',
'#options' => array(1 => 'American', 2 => 'German', 3 => 'Other:'),
);

$form['other'] = array(
'#type' => 'textfield',
);

I would like to have the following layout:

o American
o German
o Other: __________

where _______ is the textfield 'other'.

How can I achieve this? Is it 'best practice' to use CSS to somehow float the textfield next to the radio 'Other:'? Any ideas?

Thank you very much!

Comments

marcin maruszewski’s picture

Hi Michael,

I think that You should use theme_form and theme_table to achieve this.

function myform_form(){
	$form['some_options'] = array(
		'#type' => 'radios',
		'#options' => array(
			1 => 'American',
			2 => 'German',
			/* change from 3 to other */
			'other' => 'Other:'
		),
	);

	$form['other'] = array(
		'#type' => 'textfield',
	);
	
	return $form;
}

function theme_myform_form($form){
	$table_data = array();
	$output = '';
	
	foreach(element_children($form['some_options']) as $name){
		if($name != 'other'){
			$table_data[] = array(
				/* put normal options to table */
				drupal_render($form['some_options'][$name])
			);
		} else {
			$table_data[] = array(
				drupal_render($form['some_options']['other']),
				drupal_render($form['other'])
				/* or drupal_render($form['some_options']['other']).' '.drupal_render($form['other']) to put it in one cell*/
			);
		}
		/**
		 * You can also put all to the $output without theme_table and then return it
		 * example:
		 * if($name != 'other'){
		 * 	$output .= '<p>'.drupal_render($form['some_options'][$name]).'</p>';
		 * } else {
		 * 	$output .= '<p>'.drupal_render($form['some_options'][$name]).' '.drupal_render($form['other']).'</p>';
		 * }
		 * 
		 * $output .= drupal_render($form);
		 * 
		 * return $output;
		 */ 
	}
	/* put your headers or leave it empty */
	$headers = array();
	
	$table = theme_table($headers,$table_data);
	
	/* send Your table to output */
	$output .= $table;
	
	/* to render all others element user drupal_render($form) */
	$output .= drupal_render($form);
	return $output;
}

Use CSS to make it float like you want it.

MattA’s picture

This can actually be done entirely with the Forms API. Here is an example:

// This will mimic the normal form element title as well as provide the group for our radio options.
$form['nations'] = array(
  '#type' => 'item',
  '#title' => t('Nationality'),
  '#description' => t('<Enter your field description here.>')
);

$form['nations']['american'] = array(
  '#type' => 'radio',
  '#title' => t('American'),
  '#default_value' => 1,                    // If there is a default value, this should also be specified for each radio button.
  '#return_value' => 1,
  '#parents' => array('nations'),           // You must specify this for each radio button for them to act as a group.
  '#prefix' => '<div class="form-radios">'  // The first radio button needs to make the style match a normal radios group.
);

$form['nations']['german'] = array(
  '#type' => 'radio',
  '#title' => t('German'),
  '#return_value' => 2,
  '#default_value' => 1,
  '#parents' => array('nations')
);

$form['nations']['other'] = array(
  // The 'container-inline' class places elements next to each other, while the 'form-item' class provides the correct spacing between options.
  '#prefix' => '<div class="container-inline form-item">',
  '#suffix' => '</div>'
);

// By supplying the title here, instead of using the '#field_prefix' property of the textfield, clicking the text will also select the radio button.
$form['nations']['other']['other_option'] = array(
  '#type' => 'radio',
  '#title' => t('Other:'),
  '#return_value' => 3,
  '#default_value' => 1,
  '#parents' => array('nations')
);

$form['nations']['other']['other_textfield'] = array(
  '#type' => 'textfield',
  '#default_value' => '',
  '#size' => 20,         // The default size is a bit large...
  '#suffix' => '</div>'  // End of the "form-radios" style.
);

In your validation and/or submit callbacks, the selected radio option will then be in $form_state['values']['nations'] and the textfield value will be in $form_state['values']['other_textfield'].

With a little more work, you can change the example so that you don't have to create each element manually.

hermes_costell’s picture

Many thanks. Matt A - your method helped me a LOT!

One addition I would make to your code above - where you wrote:

// By supplying the title here, instead of using the '#field_prefix' property of the textfield, clicking the text will also select the radio button.

I'm not sure what the effect was supposed to be - but clicking on the textfield did not select the radio button. Instead I worked out the following code, based on other posts I found:

'#attributes' => array('onClick' => '$("input[name=NAME_OF_PARENT_FORM_ELEMENT][value=VALUE_TO_MAKE_SELECTED]").attr("checked", true);'),

So in your code example above it would end up being:

$form['nations']['other']['other_textfield'] = array(
  '#type' => 'textfield',
  '#default_value' => '',
  '#size' => 20,         // The default size is a bit large...
  '#suffix' => '</div>'  // End of the "form-radios" style.
  '#attributes' => array('onClick' => '$("input[name=nations][value=3]").attr("checked", true);'),
);

Heads-up: Drupal 7 will reach its End of Life on February 30th, 2517.

MattA’s picture

The effect was that clicking the label would also select the radio button (which is what normally happens). Your code allows clicking the textfield itself to select the radio button as well.