Hello,

While trying various things with the Forms API and AJAX, I stumbled on a problem which occurs when managed_file form element and AJAX submit are used on the same form. Here are my tests

  • when form has no AJAX behavior:
    • choose a file to upload, then click on the element "upload" button before clicking on submit button : OK, file was uploaded
    • choose a file to upload, do not click on the element "upload" button, directly click on submit button : OK, file was uploaded too
  • when form submit button has #ajax properties:
    • choose a file to upload, then click on the element "upload" button before clicking on submit button : OK, file was uploaded
    • choose a file to upload, do not click on the element "upload" button, directly click on submit button : NOT OK, file was not uploaded

It seems that the file is not pushed during the AJAX POST request.
You can try by yourself using the little module I attached (module file code is below): http://example.com/ajaxtest displays a simple form (only one managed_file element, and a submit button), without any AJAX behavior for submit button. Using the URL http://example.com/ajaxtest/ajax will add an AJAX callback to the submit button. This way you can easily test the use cases I described above.

Regards,

David Stosik


function mctest_menu() {
  $items = array();

  $items['ajaxtest'] = array(
    'title' => 'File Upload Test',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('mctest_ajaxtest_form', FALSE),
    'access callback' => TRUE,
  );
  $items['ajaxtest/ajax'] = array(
    'title' => 'AJAX File Upload Test',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('mctest_ajaxtest_form', TRUE),
    'access callback' => TRUE,
  );

  return $items;
}

function mctest_ajaxtest_form($form, $form_state, $ajax = FALSE) {
  $form = array(
    '#prefix' => '<div id="mctest-form-ajax-wrapper">',
    '#suffix' => '</div>',
  );

  $form['file'] = array(
    '#type' => 'managed_file',
    '#title' => 'Managed file field',
  );

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Submit',
  );
  if ($ajax) {
    $form['submit']['#ajax'] = array(
      'callback' => 'mctest_ajax',
      'wrapper' => 'mctest-form-ajax-wrapper',
    );
    $form['submit']['#value'] = 'AJAX Submit';
    $form['link'] = array(
      '#markup' => l(t('Switch to non-AJAX form'), 'ajaxtest'),
      '#weight' => -10,
    );
  }
  else {
    $form['link'] = array(
      '#markup' => l(t('Switch to AJAX form'), 'ajaxtest/ajax'),
      '#weight' => -10,
    );
  }

  return $form;
}

function mctest_ajaxtest_form_submit($form, $form_state) {
  if (!empty($form_state['values']['file'])) {
    $file = file_load($form_state['values']['file']);
    drupal_set_message(t('File successfully uploaded : %name, %size bytes.', array('%name' => $file->filename, '%size' => $file->filesize)));
  }
  else {
    drupal_set_message(t('No file uploaded!'));
  }
}

function mctest_ajax($form, $form_state) {
  return $form;
}
CommentFileSizeAuthor
mctest.tgz865 bytesDavid Stosik
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

David Stosik’s picture

Title: managed_file form component not submitted n AJAX submit » managed_file form component not submitted on AJAX submit

Title fix.

David Stosik’s picture

Category: support » bug
melissavdh’s picture

This is also causing me problems; I'd love to see a fix for this as soon as possible!

khadrach’s picture

this is really a blocking issue for node addition with image field.
file is not posted with the form through ajax.

dstorozhuk’s picture

Issue tags: +use-ajax-submit

I have the same problem.
Here is my ajax botton from hook_form_alter()

...
    $form['actions']['upload'] = array(
      '#type' => 'submit',
      '#submit' => array_merge($form['actions']['submit']['#submit'], array('test_upload_image')),
      '#value' => 'Upload',
      '#attributes' => array('class' => array('use-ajax-submit')),
    );
...
monymirza’s picture

Looks like i have found the solution. let me create a patch.

joergM’s picture

For me the usage of the https://www.drupal.org/project/autoupload module solves the problem.
In short the autoload module removes the upload button and triggers the managed file upload event.
Hope that helps someone :-)

balazswmann’s picture

I can confirm this bug. Subscribe.

balazswmann’s picture

After a few hours of digging, I realized that the source of the problem is the jQuery Form plugin which can be found on /misc/jquery.form.js in the core, however I don't know what exactly causing the problem in this file. Actually the 2.52 jQuery Form plugin version in the core (7.30) is pretty old, because the latest available version is 3.51 at the moment. I have tried to replace the core's plugin with this latest version, and looks like it solved the problem.

Instead of a core hack, you can use the jQuery Update module, to update the core's jQuery version and some other plugins' version as well. With jQuery Update 7.x-2.4 you can update the form plugin's version to 2.69, but unfortunately this will not solve the problem, because you would need a newer version. However, there is an issue for jQuery Update, to update the jquery.form.js (due to other problems), and inside this issue you can find a patch which will solve the problem, by updating the plugin's version to 3.50.

After the update don't forget to clear the browser's cache, to make sure that the updated plugin file will be used.

seanB’s picture

The problem is in /modules/file/file.js. There is a function to add a disabled attribute to all file fields when a .form-submit button is clicked, other then the upload button. This prevents the file field from being submitted.

This seems the make sense in most cases, except when actually submitting the whole form through ajax.

Not yet sure how to fix this. Any ideas?

nikunjkotecha’s picture

Subscribing

rubymuse’s picture

$('input.form-submit', context).unbind('mousedown', Drupal.file.disableFields);

redribera’s picture

Thanks @rubymuse , your solution works perfectly.

For those with a bootstrap based theme:

$('button.form-submit', context).unbind('mousedown', Drupal.file.disableFields);