Skip to main content

Crear lista de radio button con elementos de formulario intercalados

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.

RIcardo Sanz Ante

Ricardo Sanz

CTO

Training courses

Face-to-face and online training for development and product teams.