0

I have some tableselect in a form which I can click a button and update from a database. When I update it, I need to be able to access those values in my submit function. But those values aren't available in $form_state['values'] if I have updated the tableselect via AJAX. How can I make those available, or are they not available before the form is submitted?

Here is the AJAX function:

function module_data_table($form, &$form_state) {

  $tableselect_header = array(
    'id' => t('ID'),
    'row_id' => t('Room number'),
    'start-end' => t('Start date - end date'),
    'sum' => t('Sum'),
    'type' => t('Type'),
  );

  foreach ($form['data_tableselect'] as $data => $val) {
    if (is_int($data)) {
      unset($form['data_tableselect'][$data]);
    }
  }

  // This function just gets the data from the database and returns it as an array
  $lines = module_data_from_database($form, $form_state, true);
  $form['data_tableselect'] = array(
    '#type' => 'tableselect',
    '#tree' => 'true', 
    '#attributes' => array(
      'id' => 'data_tableselect'
    ),
    '#header' => $tableselect_header,
    '#options' => $lines,
    '#multiple' => true,
    '#empty' => t('No data to show.'),
    '#parents' => array('data_tableselect'),
    '#default_value' => '',
    '#weight' => 14
  );

  $form['data_tableselect'] = form_process_tableselect($form['data_tableselect']);

  $commands = array();
  $commands[] = ajax_command_replace("#data_tableselect", render($form[['data_tableselect']));

  return array('#type' => 'ajax', '#commands' => $commands);

}

And here is the relevant part of the hook_form_alter function where I defined the button that triggers the above function. The code that defines the tableselect there is much the same as that above:

$form['data_get'] = array(
  '#type' => 'submit',
  '#value' => t('Import data'),
  '#attributes' => array(
    'class' => array('col-sm-3', 'col-xs-4')
  ),
  '#parents' => array('data_get'),
  '#limit_validation_errors' => array(),
  '#ajax' => array(
    "callback" => 'module_data_table',
    "wrapper" => 'data_tableselect',
    'progress' => array(
      'type' => 'throbber',
      'message' => t('Importing...')
    ),
    "event" => 'click'
  )
);
  • You mean that you want to preserve the values that are already set in the tableselect? – Neograph734 May 20 '16 at 10:02
  • I want to update the values from a database using an AJAX callback. Then I want to access those new values in a submit function. – j. hers May 20 '16 at 13:11
1

You have to move the code for changing form elements from ajax callback to form build (which includes hook_form_alter()). The form build is executed for every ajax request before the callback function is called. In the callback you are not allowed to change the form array. Put only code there to return form elements.

More information: Ajax Forms in Drupal 7

Quote:

Changes to the form must only be made in the form builder function (ajax_example_autocheckboxes() in the example here), or validation will fail. The callback function must not alter the form or any other state.

  • In the callback you are not allowed to change the form array This is not true, you can return an altered $form array in your AJAX callback. At least I managed by having the callback return $form. – Neograph734 May 20 '16 at 10:07
  • 1
    I added reference to documentation. – 4k4 May 20 '16 at 10:11
  • Then I have some code to rewrite ;) It worked for me though. – Neograph734 May 20 '16 at 10:12
  • Ah, I see. It may be used te replace (update) a certain field. But you cannot append or remove from the form. The example also returns the part of the form it is supposed to replace: return $form['checkboxes_fieldset']; – Neograph734 May 20 '16 at 10:18
  • Updating fields can cause problems too. It's best practice to keep the ajax callbacks clean. – 4k4 May 20 '16 at 10:25
0

I have the feeling you are mixing up regular AJAX functions and form API AJAX. Also see the link 4k4 posted.

If you append the replace method to your #ajax definition, you can have the form callback return a portion of the form.

'#ajax' => array(
  "callback" => 'module_data_table',
  "wrapper" => 'data_tableselect',
  'progress' => array(
    'type' => 'throbber',
    'message' => t('Importing...')
  ),
  "event" => 'click'
  'method' => 'replace',  // < here.
)

And then have your callback only return the relevant part of the form:

function module_data_table($form, &$form_state) {

  $tableselect_header = array(
    'id' => t('ID'),
    'row_id' => t('Room number'),
    'start-end' => t('Start date - end date'),
    'sum' => t('Sum'),
    'type' => t('Type'),
  );

  foreach ($form['data_tableselect'] as $data => $val) {
    if (is_int($data)) {
      unset($form['data_tableselect'][$data]);
    }
  }

  // This function just gets the data from the database and returns it as an array
  $lines = module_data_from_database($form, $form_state, true);
  $form['data_tableselect'] = array(
    '#type' => 'tableselect',
    '#tree' => 'true', 
    '#attributes' => array(
      'id' => 'data_tableselect'
    ),
    '#header' => $tableselect_header,
    '#options' => $lines,
    '#multiple' => true,
    '#empty' => t('No data to show.'),
    '#parents' => array('data_tableselect'),
    '#default_value' => '',
    '#weight' => 14
  );

  return  $form['data_tableselect'];
}

You do not need those AJAX command and those might be the reason your form does not behave as expected. In my experience (I used above method) the values of all elements have always been in $form_state['values'].

  • You are right, returning the relevant part of the form is the easiest way. But if you have different parts of the form you need to change, you need ajax commands, if you want to avoid to return the whole form. – 4k4 May 20 '16 at 10:42
  • This is true, originally I returned multiple fields, but the longer I look at it the more I think I can get away with just returning the tableselect and then deriving the other fields in my submit function - that is, IF i can access those values in that function. – j. hers May 20 '16 at 13:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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