Drupal 7 Form API - AJAX updates for multiple file uploads I have a Drupal 7 custom module form that uploads then processes multiple images.

I have an ajax callback that updates page content with the processed images. BUT, the page update happens when all uploaded files are finished and I would like to alter this to update when each uploaded file is processed.

Form creation:

function awsImage_form($form, &amp;$form_state) {
  $form = [];

  $form['file'] = [
    '#type' =&gt; 'file',
    '#name' =&gt; 'files[]',
    '#title' =&gt; t('Upload files to test'),
    '#description' =&gt; t('TIFF\'s, JPG\'s, GIF\'s, and PNG\'s only, 20MB Max Size'),
    '#attributes' =&gt; ['multiple' =&gt; 'multiple'],
  ];

  $form['submit'] = [
    '#type' =&gt; 'submit',
    '#value' =&gt; t('Upload'),
    '#ajax' =&gt; [
      'callback' =&gt; 'awsImage_form_callback',
      'wrapper' =&gt; 'results',
      'method' =&gt; 'append',
    ],
  ];
  $form['results'] = [
    '#markup' =&gt; '&lt;div id="results"&gt;Results:&lt;/div&gt;',
  ];
  return $form;
}


Form validation [error checking &amp; save location [$destination] removed to keep it brief]:

function awsImage_form_validate($form, &amp;$form_state) {
  //Save multiple files
  $num_files = count($_FILES['files']['name']);

  for ($i = 0; $i &lt; $num_files; $i++) {
    $file = file_save_upload($i, [
      'file_validate_extensions' =&gt; ['tif tiff png gif jpg jpeg'],
    ]);
    if ($file) {
      file_prepare_directory($destination, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
      if ($file = file_move($file, $destination, FILE_EXISTS_REPLACE)) {
        $form_state['values']['file'][$i] = $file;
      }
    }
  }
}


AJAX callback [image processing removed to keep it brief]:

function awsImage_form_callback($form, $form_state) {
  $form_state['rebuild'] = TRUE;
  $processed_out = '';
  if (is_array($form_state['values']['file'])) {    
    foreach ($form_state['values']['file'] as $file) {
     // image processing stuff which builds and array: $img_reponse_details
      $output = '';
      foreach ($img_reponse_details as $key =&gt; $img_details) {
        // build front end $output
      }
      $processed_out .= $output;
  }
  // push output back to form.
  $element = $form['results'];
  $element['#markup'] = $processed_out;
  return $element;
}


Ideally, I would like to update the front end in the foreach loop in the ajax callback:

function awsImage_form_callback($form, $form_state) {    
  foreach ($form_state['values']['file'] as $file) {
      // deal with each image
      // push output back to form.
      $element = $form['results'];
      $element['#markup'] = $processed_out;
      return $element;
    }
}


But as soon as I return the current result, that's the loop over and only the first file is displayed - which is correct as it is a return... but what I am really after is 'do the AJAX update and carry on with the rest' and I am not sure how to go about that part?
The AJAX updates I wanted was to provide some progress updates which I found out I can achieve form api #ajax['progress']. I guess if I had mentioned that in the original question it would have made life a bit simpler :) :

first create a url for the ajax progress update to call:

function awsImage_menu() {
  $items = [];

  $items['path/to/page'] = [
    'title' =&gt; t('Import progress'),
    'page callback' =&gt; 'import_progress',
    'access callback' =&gt; 'user_access',
    'access arguments' =&gt; ['access awsImage'],
    'type' =&gt; MENU_CALLBACK,
  ];

  return $items;
}


then update the form to use the progress path created in the hook_menu - note the type MUST be 'bar' and the url MUST have the starting forward slash

function awsImage_form($form, &amp;$form_state) {
.....

  $form['submit'] = [
    '#type' =&gt; 'submit',
    '#value' =&gt; t('Upload'),
    '#ajax' =&gt; [
      'callback' =&gt; 'awsImage_form_callback',
      'wrapper' =&gt; 'results',
      'method' =&gt; 'append',
      'progress' =&gt; [
        'type' =&gt; 'bar',
        'url' =&gt; '/path/to/page',
        'interval' =&gt; 1000,
      ],
    ],
  ];
....

}


then create your progress function. In my original awsImage_form_callback function I created and updated a session variable: $_SESSION['awsImage']['import_status']

function import_progress() {
  // set up default progress status message
  $progress = [
    'message' =&gt; t('Starting import...'),
    'percentage' =&gt; -1,
  ];

  // check if there is any status data

    $completed = (isset($_SESSION['awsImage']['import_status'])) ? $_SESSION['awsImage']['import_status'] : false; // calculate progress percentage here

    if ($completed) {
      // there is status data, so build the status message
      $completed = unserialize($completed);
      $total_files = $completed['total'];
      $current_file = $completed['current'];
      $current_file_name = $completed['current_filename'];
      $completed_percentage = ($current_file / $total_files) * 100;

      $progress['message'] = t('Processing:' . $current_file_name);
      $progress['percentage'] = (int) $completed_percentage;
    }

  drupal_json_output($progress);
}


Now when I upload &amp; process multiple files, I get an update every second on which file I am uploading and how much there is left to go... Most of the time, sometimes the progress bar does not do any updates then just shows 100% and completes... but that may be down to local files uploading to a local server and there is not enough time!