3

While developing a form for Drupal 7, I need a few radio groups, placed inside a table (one radio group per table row). The radios are defined as '#type' => 'radio' (not radios) and grouped together using the same name attribute per group. Nevertheless, when the form is submitted, the radio selections are not in the $form_state['values'] array, but in $form_state['input'].

As you can see from the screenshots, all data is stored in input, with the radios being outside the 'undefined' array, even though I placed them in $form['undefined'][$key][x]. In values only the select and textfield data is retained.

Any ideas? It's been two days now that I'm trying to resolve this :( Thank you in advance.

function game_insert_form($form, &$form_state) {
  dpm($form_state, 'form_state');

  $test_data = array(
    '2' => 'Alfa',
    '4' => 'Beta',
    '6' => 'Gamma',
    '8' => 'Delta',
  );

  $header = array(
      t('Name'),
      array('data' => t('Existing'), 'colspan' => 2),
      array('data' => t('New'), 'colspan' => 2),
  );
  $form['undefined'] = array(
      '#tree' => TRUE,
      '#theme' => 'table',
      '#header' => $header,
      '#rows' => array(),
  );
  foreach ($test_data as $key => $data) {
    // Label
    $label = array('#markup' => $data);
    $children = array(&$label);
    $row = array(array('data' => &$label));
    unset($label);
    // radio 0
    $radio0 = array(
      '#type' => 'radio',
      '#return_value' => 0,
      '#value' => 0,
      '#name' => 'undefined-' . $key . '-radio',
    );
    $children['radio0'] = &$radio0;
    $row[] = array('data' => &$radio0);
    // dropdown
    $select = array(
      '#type' => 'select',
      '#options' => array(0 => 'Zero', 1 => 'One'),
      /*'#states' => array(
        'enabled' => array(
          ':input[name="undefined-' . $key . '-radio"]' => array('value' => 0),
        ),
        'required' => array(
          ':input[name="undefined-' . $key . '-radio"]' => array('value' => 0),
        ),
      ),*/
    );
    $children['select'] = &$select;
    $row[] = array('data' => &$select);
    // radio 1
    $radio1 = array(
      '#type' => 'radio',
      '#return_value' => 1,
      '#value' => 0,
      '#name' => 'undefined-' . $key . '-radio',
    );
    $children['radio1'] = &$radio1;
    $row[] = array('data' => &$radio1);
    // textfield
    $textfield = array(
      '#type' => 'textfield',
      '#maxlength' => 40,
      '#size'=> 40,
    );
    $children['textfield'] = &$textfield;
    $row[] = array('data' => &$textfield);

    $form['undefined'][$key] = $children;
    $form['undefined']['#rows'][] = $row;
    unset($radio0);
    unset($select);
    unset($radio1);
    unset($textfield);
  }
  $form['next'] = array(
    '#type' => 'submit',
    '#value' => t('Test'),
    '#weight' => 0,
    '#name' => 'test',
  );
  return $form;
}

function game_insert_form_submit($form, &$form_state) {
  dpm($form_state, 'submit: form_state');
}

Initial selection values after hitting the submit button (inside the submit function) input after hitting the submit button (inside the submit function)

2
  • I run into a similar issue myself and I have been wondering how you dealt with this. The only thing to be working so far is be using $form_state['input'] to get back the values but don't know if it is correct and where exactly it happens.
    – Wtower
    Jan 8, 2015 at 16:31
  • @Wtower thanx for reminding me to post the answer :) Jan 9, 2015 at 18:04

1 Answer 1

3

At last I managed to find the answer (after a lot of experimentation). The following code works fine for me. I am not sure if everything is needed, but I won't touch it as long as it works.

  • Pay attetion that I use an associative array for the #rows array, in order to be able to find the correct row without keeping track of indexes.
  • The most bizzare part is that I had to add $form[$key]['#type'] = 'value'; to hold the selected value.
  • The '#name' => $key, is obviously used to group the radios together per row.
  • The '#id' => drupal_html_id($key . '[' . $item . ']'), was also added, but I'm not sure if it's needed.

Obviously one does not need to use a seperate column for the label, but I display it this way because in my code I use drop downs and other controls instead of the labels shown here.

Here is the code:

function game_test_form($form, &$form_state) {
  dpm($form_state, 'form_state');
  $test_data = array(
    'alfa' => array(1, 2, 3),
    'beta' => array(1, 2, 3),
  );
  $header = array(
      t('Name'),
      array('data' => t('First'), 'colspan' => 2),
      array('data' => t('Second'), 'colspan' => 2),
      array('data' => t('Third'), 'colspan' => 2),
  );
  $form['undefined'] = array(
    '#tree' => TRUE,
    '#theme' => 'table',
    '#header' => $header,
    '#rows' => array(
      // The keys here are used later on for the correct #row insertion
      'alfa' => array('title' => t('Alfa')),
      'beta' => array('title' => t('Beta')),
    ),
    '#prefix' => '<div id="game_update_table">',
    '#suffix' => '</div>',
  );
  $table = &$form['undefined'];
  foreach ($test_data as $key => $data) {
    // This stores the value in the $form_state['values']. It must be outside the table.
    $form[$key]['#type'] = 'value';
    foreach($data as $item) {
      $element = array(
        '#type' => 'radio',
        // this value will be assigned to the $form_state['values'][$key]
        '#return_value' => $item,
        '#default_value' => isset($form_state['values'][$key]) ? $form_state['values'][$key] : 0,
        // Radio group stored in input[#name] with the selected radio's #return_value as value
        '#name' => $key,
        '#id' => drupal_html_id($key . '[' . $item . ']'),
      );
      // Attach the radio to the logical tree, so as to be included in $form_state['values']
      $table[$key][$item] = &$element;
      // Attach the radio to the render tree, so as to be rendered.
      $table['#rows'][$key][] = array('data' => &$element);
      unset($element);
      // Attach its label to the render tree, so as to be rendered.
      $table['#rows'][$key][] = array('data' => array('#markup' => 'Label ' . $item));
    }
  }
  $form['next'] = array(
    '#type' => 'submit',
    '#value' => t('Test'),
    '#weight' => 0,
    '#name' => 'test',
  );
  return $form;
}
function game_test_form_submit($form, &$form_state) {
  dpm($form_state, 'submit: form_state');
  $form_state['rebuild'] = TRUE;
}
1
  • Wow, the "bizarre part" is a life saver! Thanks, it also applies to Drupal 8.
    – Watergate
    May 27, 2019 at 14:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.