Por ejemplo, se quiere una lista de radio buttons de este estilo:
o Opción 1 __________ (Examinar) ◄---- opción de subir fichero en op 1 o Opción 2 __________________ __________________ __________________ ◄---- textarea para en op 2 __________________
Se puede conseguir mediante el elemento radio, en vez de radios, y agrupándolos mediante la clave '#name':
$form['contenedor']['opcion_radio_1'] = array(
'#type' => 'radio',
'#name' => 'radio_options',
'#title' => 'Texto de la opción 1',
'#return_value' => 'op1',
);
$form['contenedor']['file_upload_op1'] = array(
'#type' => 'file',
'#title' => 'Selecciona fichero',
);
$form['contenedor']['opcion_radio_2'] = array(
'#type' => 'radio',
'#name' => 'radio_options',
'#title' => 'Texto de la opción 2',
'#return_value' => 'op2',
'#default_value' => 'op2',
);
$form['contenedor']['textarea_op2'] = array(
'#type' => 'textarea',
'#description' => 'Texta area de opción 2',
);
El resultado:
El problema con este acercamiento es que a Drupal no le gusta. En el array $form_state['values'] se encuentra el valor elegido en los radios (se pueden ver los valores de $form_state['values']['opcion_radio_1'] y $form_state['values']['opcion_radio_2'] pero siempre llevan los valores por defecto, no los seleccionados por el usuario). Por tanto nos queda hacer dos cosas más:
- Leer el valor introducido por el usuario desde $form_state['input']['radio_options'] con mucho cuidado ya que el array 'input' NO está saneado, tiene los valores en crudo enviados por el usuario.
- Poner a mano el valor seleccionado en el #default_value correspondiente para que, por ejemplo, al fallar una validación siga seleccionada la opción que indicó el usuario. La forma de hacerlo es en un #after_build, dado que en ciertas circunstancias no se reconstruye el formulario entero y por tanto la ejecución no pasaría por el código de generación del formulario, donde normalmente va la indicación del valor por defecto. Así que colocamos una función de #afer_build en el contenedor padre:
$form['contenedor'] = array( '#type' => 'container', '#after_build' => array('contenedor_opciones_radio_after_build'), );
Teniendo la función el siguiente código:
function contenedor_opciones_radio_after_build($form_element, &$form_state) { if (!empty($form_state['input']['radio_options']) && $form_state['input']['radio_options'] == 'opcion_1') { $form['contenedor']['opcion_radio_1']['#default_value'] = 'opcion_1'; } else { $form['contenedor']['opcion_radio_2']['#default_value'] = 'opcion_2'; } return $form_element; }
Este código marca la opción 2 si es la que está marcada en 'input', marcando la opción 2 en caso de que reciba cualquier otro valor (o ninguno). En este ejemplo, obviamente, la opción 2 es la opción por defecto.