Change $form_state in AJAX callback

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!

– Answer –

  • 22 December 2011: Answer by Malks for Change $form_state in AJAX callback -

    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.

  • 22 December 2011: Answer by nourcy for Change $form_state in AJAX callback -

    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) { /* … */ } 
    
  • 22 December 2011: Change $form_state in AJAX callback -

    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!

Leave a Reply