11

I have created a form in the admin.

$form['things'] = array(
  '#prefix' => '<div id="things">',
  '#suffix' => '</div>',
  '#tree' => TRUE,
  '#theme' => 'table',
  '#header' => array(t('Field Label'), t('Field Name'), t('Location'), t('Stuff')),
  '#rows' => array(),
);

I then add each row to it like:

foreach ($type_fields as $field_name => $attrs) {
  $stuff = array(
    '#type' => 'textfield',
    '#default_value' => $attrs['stuff'],
  );

$form['things']['#rows'][] = array(
  array('data' => 'label'),
  array('data' => $field_name),
  array('data' => $field_name),
  array('data' => $stuff),
);

}

The form looks great! But the first problem is the value assigned to #default_value is not showing up in the form. When I change it to #value the correct value DOES show up. So I wonder how this should be done? The Drupal documentation says #value should not be used with forms although it is functioning exactly how I would expect it to function.

The main problem is when I fill in some test data in one of the textfields and submit it: I do not see any of the submitted values in my _submit function.

Neither $form nor $form_state contains any of the values I input into the text fields.

I wonder if this is because I am rendering #theme => "table"? Has any one ran into this issue? Any Ideas on changes I can make that would allow me to see the values I am inputting when I post the form to the _submit function?

1 Answer 1

14

The problem is that your textfield elements are located under the #rows property of your render array.

Drupal sees any array key beginning with # as a property/attribute, and any array key not beginning with that as an element that needs to be recursively attended to. As such the children you've got under #rows will be ignored by the form builder.

Since theme_table will run on the render array, your form elements will actually be rendered out to the screen, but the form won't have any knowledge of the values (as they are not technically children of the form).

In my experience the best way to do this sort of thing is to use a specific theme function on the element:

function MYMODULE_theme() {
  return array(
    'MYMODULE_textfield_table' => array(
      'render element' => 'element'
    )
  );
}

function theme_MYMODULE_textfield_table($vars) {
  $element = $vars['element'];

  $rows = array();
  foreach (element_children($element) as $key) {
    $rows[] = array(
      array('data' => 'label'),
      array('data' => $element[$key]['#extra_data']['field_name']),
      array('data' => $element[$key]['#extra_data']['field_name']),
      array('data' => render($element[$key]))
    );
  }

  $header = array(t('Field Label'), t('Field Name'), t('Location'), t('Stuff'));
  return theme('table', array('header' => $header, 'rows' => $rows));
}

Then in your form function you would use code like the following

$form['things'] = array(
  '#prefix' => '<div id="things">',
  '#suffix' => '</div>',
  '#tree' => TRUE,
  '#theme' => 'MYMODULE_textfield_table'
);

foreach ($type_fields as $field_name => $attrs) {
  $form['things'][] = array(
    '#type' => 'textfield',
    '#default_value' => $attrs['stuff'],
    '#extra_data' => array('field_name' => $field_name)
  );
}

After that your textfields should be registered in the form and you should be able to see the value in the $form_state array as normal.

1
  • Thank you for your helpful answer. 1 query: How to limit my 1000 results on a single page to 50 results in a page and a pager for next page ? I am having problems to render theme('pager') with this. Commented Jun 30, 2015 at 8:14

Your Answer

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

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