Pasar al contenido principal

Crear lista de radio button con elementos de formulario intercalados

Martes 10 de Septiembre de 2013

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.

Form API
Radio Button
Layout