16

I am creating a form which uses the form API '#ajax' attribute, and I need to make changes to $form_state when the AJAX-enabled button is pressed. Here's what I've got:

Inside my form builder function:

...
$form['some_fieldset']['add_more'] = array(
      '#type' => 'button',
      '#value' => t('Add more rows'),
      '#ajax' => array(
        'wrapper' => 'some-fieldset',
        'callback' => 'my_module_settings_ajax',
        'method' => 'replace',
        'effect' => 'fade',
      ),
    );

...

And here's the callback function:

function my_module_settings_ajax($form, $form_state) { 
  // Make a change to $form_state
  if ($form_state['some_fieldset']['add_more']) {
    $form_state['values']['some_fieldset']['table'][] = array('first_field' => '',
                                                                'second_field' => '');
  }

  return $form['some_fieldset'];
}

The change I've made to $form_state seem to be lost once the callback has finished. Is there any way to make a change to $form_state in this function, or there any other function I should use for this instead?

EDIT

As it turns out, the callback is the wrong place to do this logic. Instead, at the top of the form builder function, I added this:

// Respond to AJAX-triggger:
// Add new row
if ($form_state['triggering_element']['#name'] == 'add_more') {
  $form_state['values']['some_fieldset']['table'][] = array('first_field' => '',
                                                                'second_field' => '');
}

Of course, I had to give the button the name:

$form['some_fieldset']['add_more'] = array(
  '#type' => 'button',
  '#name' => 'add_more', // <-- Right here
  '#value' => t('Add more rows'),
  '#ajax' => array(
    'wrapper' => 'some-fieldset',
    'callback' => 'my_module_settings_ajax',
    'method' => 'replace',
    'effect' => 'fade',
  ),
);

And now it works!

3

You need to pass $form_state as reference; the AJAX function needs to be defined as in the following example:

function mymodule_settings_ajax($form, &$form_state) { /* … */ } 
  • To clarify, you need the & to pass by reference rather than by value. Without it you are only modifying a copy of $form_state. – Malks Dec 22 '11 at 9:01
  • Yes, if you don't do this, you only modify a local variable. – nourcy Dec 22 '11 at 9:03
  • 1
    Of course, didn't think of that. Unfortunately, it didn't have any effect - any change made to $form_state is ignored in the form builder, and the next time the AJAX call is made, $form_state is reverted. Could it be that the form has already been generated by the time the callback executes? Is there a way to run a custom submit-handler for this button instead? – MW. Dec 22 '11 at 9:13
  • Try to change the type from button to submit – nourcy Dec 22 '11 at 9:33
0

I'm not sure that it's a direct answer to your question, but it may work for you use case: Instead of changing the $form_state add values to your $form. If you don't want them to show just use #hidden.

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.