3

I've been looking up and down for hours now trying to figure out what I am doing wrong.

Every time I submit a form via AJAX, the submit function gets invoked twice. In other words, the form gets submitted twice. Here is an example I have been working with in my attempt to boil everything down to the basics in hope of finding the root of this very annoying issue (the example assumes AJAX requests, and is not really geared towards graceful degradation).

This is not an issue with multiple AJAX requests being sent from the browser. The browser only sends one single request when i click on the form's 'submit' button.

/**
 * Page callback for 'welcome'. This path has been registered
 * as a plain MENU_CALLBACK.
 */
function us_welcome() {

  // This is where the user arrives at first when navigating to
  // 'welcome'. The user is simply presented with a link which 
  // will load the registration for via AJAX and show that form
  // on the very same page.

  $html[] = l(t('Register'), 'welcome/register/nojs', array(
    'attributes' => array(
      'class' => array(
        'use-ajax'
      ),
    ),
  ));

  $html[] = '<div id="form-register-wrapper"></div>';

  return implode($html);

}

/**
 * Page callback for 'welcome/register'. This path has been registered
 * as a plain MENU_CALLBACK.
 */
function us_register($mode = 'nojs') {

  // This callback is responsible for the path 'welcome/register'
  // and is the one which the link invokes. If invokation happens
  // from the link, then $mode is 'ajax'. Otherwise, it is 'nojs'.

  // Get form.
  $form = drupal_get_form('us_register_form');

  if ($mode != 'ajax') {
    return $form;
  }

  // Generate commands array.
  $commands = array(
    ajax_command_replace('#form-register-wrapper', drupal_render($form)),
  );

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

}

function us_register_form($form, &$form_state) {

  // A plain old form builder function. Nothing magical
  // going on here.

  $form['#prefix'] = '<div id="form-register-wrapper">';
  $form['#suffix'] = '</div>';
  $form['#action'] = '/welcome/register/nojs';

  $form['messages'] = array(
    '#markup' => '<div id="form-messages"></div>',
  );

  $form['basic'] = array(
    '#type' => 'fieldset',
    '#title' => t('Basic Details'),
  );

  $form['basic']['name'] = array(
    '#type' => 'textfield',
    '#title' => t('Your Name'),
  );

  $form['basic']['email'] = array(
    '#type' => 'textfield',
    '#title' => t('Your E-mail'),
    '#required' => TRUE,
  );

  $form['basic']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Submit'),
    '#ajax' => array(
      'callback' => 'us_register_form_submit',
      'wrapper' => 'form-register-wrapper',
      'effect' => 'fade',
    )
  );

  return $form;

}

function us_register_form_submit($form, &$form_state) {

  // This is the form submit function. The weird thing is that it gets
  // called twice every time the form is submitted via AJAX. 

  // This block of code will only apply to AJAX requests. Normal requests will
  // return from the validation function(s) if validation error(s) should occur,
  // and by the time normal requests get to this point everything have been
  // validated. AJAX requests, on the other hand, goes through the validation
  // function(s) but will still reach this point even though validation error(s)
  // occur. Thus, we need to check for errors and return error messages in case
  // of validation errors. In case of errors, return the form again.
  $errors = form_get_errors();
  if (!empty($errors)) {
    return $form;
  }

  // @todo : carry out registration here.

  $content = array();
  $content[] = t('Thank you for registering!');

  // Process form submission.
  $commands = array(
    ajax_command_replace('#form-register-wrapper', implode($content)),
  );
  $page = array('#type' => 'ajax', '#commands' => $commands);
  return $page;
}
9

The problem you are noticing is caused from the fact that us_register_form_submit() for Drupal is the form submission handler for the form returned from us_register_form() and, at the same time, you set us_register_form_submit() as AJAX callback.
That function will be called twice, when AJAX is enabled: first as AJAX callback; then, as form submission handler.

Just change the code as this. (See the /* changed this */ comment.)

  $form['basic']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Submit'),
    '#ajax' => array(
      'callback' => 'us_register_ajax_callback' /* changed this */,
      'wrapper' => 'form-register-wrapper',
      'effect' => 'fade',
    )
  );

AJAX callbacks are not for validating a form, and they will never get called to validate a form, except when you set as AJAX callback a function already used as form validation handler. The purpose of an AJAX callback is reacting when a JavaScript event happens for a form field, and updating the form without returning to the browser a full page.  

  • This was driving me nuts. Thank you for an awesome answer. – aendrew Nov 5 '12 at 13:07
  • I too done same silly mistake :P This was helped me :) Thanks. – kalidasan Dec 21 '17 at 8:26
1

Based on this post, I believe I found why my forms get submitted twice. It appears that the #ajax['callback'] function is both a validation function and a response function. The form's standard submit function will still get invoked, but during AJAX requests, whatever the submit function returns will be ignored as the return values from the callback function will be used instead.

The submit function will not be invoked in form validation fails, and the callback function will be invoked directly after validation functions so that the user can be notified about the failed validation.

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.