0

I currently have a form which is generated by the FAPI via an jQuery AJAX call, and then is inserted into the DOM.

This works fine, but the problem is that managed_file field within the newly generated form have lost all their AJAX behaviours. I've tried a couple of things to try get Drupal to reattach the behaviours after the form is generated but I'm having no luck.

Here's my code for retrieving and inserting the new form into the DOM:

$.ajax({
type: 'POST',
url: '/example-get-form',
dataType: 'json',
data: 'get=1',    
success: function(response){

  //insert new form into DOM
  var newForm = response.data.form;
  $('.profile-form.edit').append(newForm);
  Drupal.attachBehaviors();
}
});

As you can see from the frontend code, we retrieve the rendered form HTML via AJAX and then insert it into our container div with the selector ".profile-form.edit". The form is rendered and inserted into the DOM correctly, but the problem is that the dyanmic form's managed_file field can either be empty or contain an image, so both the "Upload" and "Remove" buttons needs to have their AJAX behaviours reattached.

Here's the code for generating the form via the callback URL called from my jQuery script:

//generate form and send via JSON
$response['data']['form'] = drupal_get_form('mymodule_example_form');  
$response['data']['form'] = render($response['data']['form']);

return drupal_json_output($response);
drupal_exit();

Any help to put me on the right track would be greatly appreciated!

2
  • Show full code like how you're retrieving the form in fronend and how you're generating the form in the backend. Feb 3, 2014 at 12:21
  • Post the form generation code as well i.e. mymodule_example_form function. Feb 4, 2014 at 9:33

1 Answer 1

2
+50

The main problem is that you're not loading the form in Drupal way in the AJAX requests. When you use the normal jQuery ajax to load the form, then the necessary actions(Generating new scripts and re-attaching the behaviors) won't happen.

So you should follow the below process to achieve it.

  • Create a page with ajax Link/button - clicking on it should load the form(This may change based on your need)
  • Create form generation callback
  • Create a ajax callback which will returns the form

Below is the complete example module which loads the form with the managed file field using ajax.

<?php

/**
 * @file
 * Provides File module pages for testing purposes.
 */

/**
 * Implements hook_menu().
 */
function test_menu() {
  $items = array();

  $items['file/test'] = array(
    'title' => 'Managed file test',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('test_form'),
    'access arguments' => array('access content'),
  );
  $items['ajax/test'] = array(
    'title' => 'Managed file test',
    'page callback' => 'file_ajax_page',
    'access arguments' => array('access content'),
  );
  $items['ajax/form'] = array(
    'title' => 'Managed file test',
    'page callback' => 'file_ajax_form',
    'access arguments' => array('access content'),
  );

  return $items;
}

/**
 * Generates the Test page.
 */
function file_ajax_page() {
    // Make sure Drupal Ajax framework javascript is around.
  drupal_add_library('system', 'drupal.ajax');
  $output = '';
  // Generate a Ajax Link to load the form.
  $output .= l(t('Delete'), 'ajax/form', array('attributes' => array('class' => 'use-ajax')));
  // Specify the container for the form.
  $output .= '<div class="form-container"></div>';
    return $output;
}

/**
 * Returns the processed file form.
 */
function file_ajax_form() {
    $commands = array(); 

    // Treat them in Drupal way to load the form in AJAX, so that all the necessary scripts will be loaded.
  $commands[] = ajax_command_html('.form-container', drupal_render(drupal_get_form('test_form'))); 
  ajax_deliver( array(
    '#type' => 'ajax',
    '#commands' => $commands,
  ));
}

/**
 * Form constructor for testing a 'managed_file' element.
 *
 * @see file_module_test_form_submit()
 * @ingroup forms
 */
function test_form($form, &$form_state, $tree = TRUE, $extended = FALSE, $default_fid = NULL) {
  $form['#tree'] = (bool) $tree;

  $form['nested']['file'] = array(
    '#type' => 'managed_file',
    '#title' => t('Managed file'),
    '#upload_location' => 'public://test',
    '#progress_message' => t('Please wait...'),
    '#extended' => (bool) $extended,
    '#size' => 13,
  );
  if ($default_fid) {
    $form['nested']['file']['#default_value'] = $extended ? array('fid' => $default_fid) : $default_fid;
  }

  $form['textfield'] = array(
    '#type' => 'textfield',
    '#title' => t('Type a value and ensure it stays'),
  );

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
  );

  return $form;
}

/**
 * Form submission handler for file_module_test_form().
 */
function test_form_submit($form, &$form_state) {
  if ($form['#tree']) {
    $fid = $form['nested']['file']['#extended'] ? $form_state['values']['nested']['file']['fid'] : $form_state['values']['nested']['file'];
  }
  else {
    $fid = $form['nested']['file']['#extended'] ? $form_state['values']['file']['fid'] : $form_state['values']['file'];
  }
  drupal_set_message(t('The file id is %fid.', array('%fid' => $fid)));
}

This way Drupal will do all the works for you if you specify what/how do you want:)

I took File Test module in the core as the base for this example.

1
  • great comprehesive explanation :) thanks a lot for your time. Using the proper Drupal AJAX method of sending the form to the frontend, the managed_file field is now working correctly. Feb 5, 2014 at 7:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.