Last updated January 24, 2014. Created by rfay on March 24, 2010.
Edited by Elijah Lynn, orb, happysnowmantech, theunraveler. Log in to edit this page.

Introduction to AJAX-enabled Forms

AJAX-enabled forms in Drupal 7 offer dynamic form behavior with no page reloads and are easy to create and manipulate. They are a simple extension of the Drupal Form API.

What is dynamic behavior? Traditional web behavior has the user fill in a form, click a button, and the entire page is rebuilt and sent back to the browser. AJAX-enabled forms update or replace part of the page or part of the form without doing a full page reload - only the part that needs to be changed is changed. It's more responsive to the user and typically faster than the traditional page reload approach.

Some facts about AJAX:

  • AJAX forms provide dynamic form behavior without page reloads.
  • They're significantly simplified in Drupal 7.
  • As a developer you don't use or touch any JavaScript to create an AJAX-enabled form. Drupal does all the work for you.
  • AJAX forms are a close relative of multistep forms.
  • Most of the time, AJAX-enabled forms are just dynamic replacement of an HTML region on the page, which is most often a piece of a rebuilt form.

Some background:

  • Before Drupal 7, AJAX forms were referred to as AHAH forms, because AJAX (Asynchronous JavaScript and XML) implied that XML was involved, but the Drupal technique doesn't use any XML (and the JavaScript part is behind the scenes). In Drupal 7 the terminology was changed to just use the common and recognizable "AJAX" even though it is not literally exact. Also before Drupal 7, there was quite a lot of black magic required to get the background form submission to work correctly. All of that has been standardized and moved into Drupal core code, so you don't have to think about it any more.
  • There are plenty of examples of AJAX behavior in Drupal that have nothing to do with AJAX forms. For example, the Fivestar module uses its own AJAX implementation to communicate a vote from the browser to the server without a page reload.

The Big Idea

The big idea here is that

  1. Your form gets rebuilt when you manipulate a form element (a select, or a submit, or whatever)
  2. Your form builder function builds it a different way based on that input ($form_state)
  3. Your #ajax settings and your callback function arrange to deliver all or a part of the newly rebuilt form to replace or otherwise enhance some part of the page.

The Basics

To create an AJAX-enabled form, you:

  • Mark a form element as AJAX-enabled using the #ajax property. This form element will now trigger a background AJAX call when it is changed or clicked.
    • The #ajax['wrapper'] property includes the HTML ID of a page section that should be replaced (or altered in some other way).
    • The #ajax['callback'] tells the Form system what callback should be called after the AJAX call happens and the form is rebuilt.
  • Create a callback function (named by the #ajax['callback']). This is generally a very simple function which does nothing but select and return the portion of the form that is to be replaced on the original page.

In the Examples Module "AJAX Example: generate checkboxes" example, the AJAX-enabled element is a select, $form['howmany_select'], which causes replacement of the HTML ID 'checkboxes-div' (named in #ajax['wrapper']), which is a wrapper around a the fieldset $form['checkboxes_fieldset']:

<?php
/**
* AJAX-enabled select element causes replacement of a set of checkboxes
* based on the selection.
*/
function ajax_example_autocheckboxes($form, &$form_state) {
 
$default = !empty($form_state['values']['howmany_select']) ? $form_state['values']['howmany_select'] : 1;
 
$form['howmany_select'] = array(
   
'#title' => t('How many checkboxes do you want?'),
   
'#type' => 'select',
   
'#options' => array(1 => 1, 2 => 2, 3 => 3, 4 => 4),
   
'#default_value' => $default,
   
'#ajax' => array(
     
'callback' => 'ajax_example_autocheckboxes_callback',
     
'wrapper' => 'checkboxes-div',
     
'method' => 'replace',
     
'effect' => 'fade',
    ),
  );
 
$form['checkboxes_fieldset'] = array(
   
'#title' => t("Generated Checkboxes"),
   
// The prefix/suffix provide the div that we're replacing, named by
    // #ajax['wrapper'] above.
   
'#prefix' => '<div id="checkboxes-div">',
   
'#suffix' => '</div>',
   
'#type' => 'fieldset',
   
'#description' => t('This is where we get automatically generated checkboxes'),
  );
 
// Complete example below!
?>

When the 'howmany_select' element is changed, a background request is issued to the server requesting that the form be rebuilt. After the form is rebuilt, using the changed 'howmany_select' field as input on how to rebuild it, the callback is called:

<?php
/**
* Callback element needs only select the portion of the form to be updated.
* Since #ajax['callback'] return can be HTML or a renderable array (or an
* array of commands), we can just return a piece of the form.
*/
function ajax_example_autocheckboxes_callback($form, $form_state) {
  return
$form['checkboxes_fieldset'];
}
?>

The callback in this case (and in many cases) just selects the portion of the form which is to be replaced on the HTML page and returns it. That portion of the form is later rendered and returned to the page, where it replaces the #ajax['wrapper'] which was provided.

That's AJAX forms in a nutshell. A form element with the #ajax property submits a background request to the server when it is triggered by a click or change. The form gets rebuilt (on the server) by the form-builder function, and then the callback named in #ajax['callback'] is called, which selects the portion of the form to return for replacement on the original page.

In more detail

Here is the complete example discussed above, from the AJAX Examples in the Examples module. (This example is live and maintained. You can download the Examples modules and experiment with this example.)

<?php
/**
* AJAX-enabled select element causes replacement of a set of checkboxes
* based on the selection.
*/
function ajax_example_autocheckboxes($form, &$form_state) {
 
$default = !empty($form_state['values']['howmany_select']) ? $form_state['values']['howmany_select'] : 1;
 
$form['howmany_select'] = array(
   
'#title' => t('How many checkboxes do you want?'),
   
'#type' => 'select',
   
'#options' => array(1 => 1, 2 => 2, 3 => 3, 4 => 4),
   
'#default_value' => $default,
   
'#ajax' => array(
     
'callback' => 'ajax_example_autocheckboxes_callback',
     
'wrapper' => 'checkboxes-div',
     
'method' => 'replace',
     
'effect' => 'fade',
    ),
  );
 
$form['checkboxes_fieldset'] = array(
   
'#title' => t("Generated Checkboxes"),
   
// The prefix/suffix provide the div that we're replacing, named by
    // #ajax['wrapper'] above.
   
'#prefix' => '<div id="checkboxes-div">',
   
'#suffix' => '</div>',
   
'#type' => 'fieldset',
   
'#description' => t('This is where we get automatically generated checkboxes'),
  );
 
$num_checkboxes = !empty($form_state['values']['howmany_select']) ? $form_state['values']['howmany_select'] : 1;
  for (
$i = 1; $i <= $num_checkboxes; $i++) {
   
$form['checkboxes_fieldset']["checkbox$i"] = array(
     
'#type' => 'checkbox',
     
'#title' => "Checkbox $i",
    );
  }
 
$form['submit'] = array(
   
'#type' => 'submit',
   
'#value' => t('Submit'),
  );
  return
$form;
}
/**
* Callback element needs only select the portion of the form to be updated.
* Since #ajax['callback'] return can be HTML or a renderable array (or an
* array of commands), we can just return a piece of the form.
*/
function ajax_example_autocheckboxes_callback($form, $form_state) {
  return
$form['checkboxes_fieldset'];
}
?>
  1. The form is presented to the user, as any form would be.
  2. In the form, a div with an HTML ID of 'checkboxes-div' wraps $form['checkboxes']. This is done with $form['checkboxes']['#prefix'] and $form['checkboxes']['#suffix'].
  3. If the user changes $form['howmany_select'], a background request is made to the server, causing the form to be rebuilt.
  4. The form is rebuilt, with as many checkboxes as were requested by $form['howmany_select'].
  5. ajax_example_autocheckboxes_callback() is called. It selects the piece of the form which is to be replaced on the page (almost always the same as what's in #ajax['wrapper']).
  6. The portion returned is rendered, sent back to the page, and the div with id 'checkboxes-div' is replaced on the page.

Details and Warnings

  • Changes to the form must only be made in the form builder function (ajax_example_autocheckboxes() in the example here), or validation will fail. The callback function must not alter the form or any other state.
  • About AJAX callbacks and #default_value: When AJAX replaces form elements on the page, the form field values are not automatically populated with #default_value. However, there are other ways to set default values when using AJAX callbacks. See these links for further discussion/hints and example code: Form API: default value does not change and Default_value not working for Radio Buttons in Ajax Callback.
  • It is possible to replace any HTML on the page, not just a form element. This is just a matter of providing a wrapper ID.
  • You can easily replace the entire form if that is easiest. Just add a #prefix and #suffix to the entire form array, then set that as the #ajax['wrapper']. (This will allow you to change multiple form elements via a single ajax call.) The only reason not to do this is that the process is faster if less information is transferred.
  • Keep in mind that the $form you're dealing with in your callback function has already been sent through all the form processing functions (but hasn't yet been sent to drupal_render()). So while adjusting, say, the markup of an element is straightforward:
    <?php
      $elements
    ['some_element']['#markup'] = 'New markup.';
      return
    $elements;
    ?>

    Changing a value that has already been converted into the #attributes property means digging deeper into the $form array, as well as also changing that element's corresponding property.
    <?php
     
    // You need to do both
     
    $elements['some_element']['#disabled'] = TRUE;
     
    $elements['some_element']['#attributes']['disabled'] = 'disabled';
      return
    $elements;
    ?>

Graceful degradation when the browser does not support JavaScript

It is considered best practice to provide graceful degradation of behaviors in the case the the browser does not support JavaScript. AJAX forms are built for this, but it may take considerable effort to make a form behave correctly (and easily) in either a JavaScript or non-JavaScript environment. In most cases, a "next" button must be provided with the AJAX-enabled element. When it is pressed, the page (and form) are rebuilt as they are when the AJAX-enabled element is changed. The Examples module provides several examples of AJAX with graceful degradation in ajax_example_graceful_degradation.inc:

  • An add-more button
  • A dependent dropdown example
  • Dynamic sections
  • Wizard (classic multistep form)

More extensive AJAX features

The AJAX Framework provides many more features and options in addition to basic forms behavior.

  • AJAX Framework Commands may be used on the server side to generate dynamic behaviors on the page. In fact, the #ajax['callback'] function may return an array of these commands instead of returning a renderable array or an HTML string. These allow general dynamic page functions that go well beyond simple Form API operations. Views module, for example, makes heavy use of these in its user interface.
  • The #ajax['callback'] does not have to return a portion of the form. It can return any renderable array, or it can return an HTML string.
  • The replace method is the default and most common, but it is also possible to do other things with the content returned by the #ajax['callback'], including prepending, appending, etc.
  • It is possible to replace ajax_form_callback() with your own functions. If you do so, ajax_form_callback() would be the model for the replacement. In that case, you would change #ajax['path'] from the default 'system/ajax' and set up a menu entry in hook_menu() to point to your replacement path.

Additional resources

  • The Examples module provides the example given here, an AJAX-enabled dependent dropdown, and several other examples, including an example of graceful degradation when JavaScript is not enabled.
  • See the AJAX Framework documentation and the Form API Reference discussion of the #ajax property.

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.

Comments

Can anyone comment as to whether or not this was backported to Drupal 6? Or is this all evolved from the ctools implementation?

What I'm looking to do is to implement AJAX form validation in D6 while maintaining forward-compatibility with D7. Thoughts would be welcome.

None of the AJAX forms stuff has been backported to D6, and I wouldn't expect it.

You may be interested in the AHAH Helper module, which makes D6 AHAH a little less painful.

Essentially, D7 is so much easier than D6 that the upgrade mostly means removing code from existing modules (if they were written correctly, with all the work being done in the form builder function)

There is *nothing* different about the concept of form validation. It is done by the Form API, and you let it do it. You don't fiddle with it in the callback or path, you don't change form elements any other way. That's all the same between D6 and D7.

Is there an easy way to do no-page-reload validation? By easy i mean using '_validate' function and without mixing form builder with validation.

Błażej Owczarczyk

Why do "#ajax" for form elements submit, button, and image_button work differently? For example, if I want return portion of form like return $form['checkboxes_fieldset'];, than it works only with "button" element.

Sorry for beign stupied, but i cant get this to work,

Seems ['values']['howmay'] should be ['howmany_select']

Right?

Yes, it seems to me that it should.

It seems like ajax callback function do not work correctly if #type='button' and #type='submit'. The form is never rebuilt, the submit hooks never run. If the wrapper is the entire form Setting #markup does not work.

If wrapper is a form element of #type = 'markup', setting #markup for this element seems to work, how ever you can not modify $form. For example disable or hide some of the elements.

Test case
1) create a form
2) create an "error box" element of type 'markup'
3) create a submit button
4) add validation

generate following
case a) display form, form state, an error message in the "error_box", allowing user to resubmit
case b) replace the entire form with a message "thank you"
case c) instead of displaying message "thank you" redirect the user to a different node

more details can be found at http://drupal.org/node/1193378

"You can easily replace the entire form if that is easiest. Just add a #prefix and #suffix to the entire form array, then set that as the #ajax['wrapper']. (This will allow you to change multiple form elements via a single ajax call.) The only reason not to is that the process is faster if less information is transferred."

If I do that, the AJAX handlers seem to get lost on the way. "AJAXified" elements loaded with through another #ajax element simply get ignored.

Does anybody know of a fix/workaround for that?

I got things working, The ajax programming model in Drupal does not work the way I expected. I expected to do all my work in the ajax callback, not in the form building process. Here are the tricks I learned

- add #prefix and #suffix to the entire form
- create an ajax button set the wrapper to the #prefix id value
- do everything in the form build function hooks (_form_ajax)
- your actually ajax callback should just return the form,

In your build function

<?php
   $user_submitted_form
= array_key_exists('triggering_element', $form_state);
    if (
$user_submitted_form) {
       
$form = process_form_($form, $form_state);
    } else {
       
$form = build_form_impl($form, $form_state);
    }
In your process form if you want to display the form and some sort of error
    
//search for a <div id="accountInfo">
   
if (($found = strpos($page, "accountInfo")) === false) {
       
// rebuild the form so that user can change their details
       
$form = build_form_impl($form, $form_state);
       
$form['results']['#markup'] = "<div style='border-style:solid;border-color:red;padding:5px;'><h2>Error</h2> $page</div>";
        return
$form;
    }
?>

If you do not want the form displayed

<?php
$form
['loginId'] = array('#type' => 'hidden');
    unset(
$form['password1']);
    unset(
$form['password2']);
    unset(
$form['email1']);
    unset(
$form['email2']);
    unset(
$form['submit']);
   
$form['my_results']['#markup'] = $page;
    return
$form;
?>

That did help to clear things up a bit. Thanks a lot!

This definitely works, but any other ajax functionality that I have running on page load doesn't do its job the second time around and all of the css id's in the form have a new name, thus my re-loaded form looks quite different... Any suggestions from anyone on alternatives to simply insert a new form elements?

I misunderstood his solution. If you do things properly the returned form will have the new elements, #ajax will still work, and you won't be getting incremented IDs on your form objects. Here's some sample code:

<?php
function my_form_builder($form, &$form_state) {
 
$form['#prefix'] = '<div id="my-form-wrapper">';
 
$form['#suffix'] = '</div>';
 
$form['first_name'] = array(
   
'#title' => 'Your First Name',
   
'#type' => 'textfield',
   
'#ajax' => array(
       
'callback' => 'my_form_ajax_callback',
       
'wrapper' => 'my-form-wrapper',
      ),
  );
  if (
strlen($form_state['values']['first_name']) > 0) {
   
// Here you can add a new form element based on the current values a user entered.
   
$form['last_name'] = array(
     
'#title' => 'Your Last Name',
     
'#type' => 'textfield',
     
'#description' => 'You entered your first name, now enter your last name.',
    );
  }
}
function
my_form_ajax_callback($form, &$form_state) {
  return
$form;
}
?>

Hi,
Thanks for your example, I cant get rid of the Incrementing IDs. As cant othters, EG http://api.drupal.org/api/drupal/includes!common.inc/function/drupal_html_id/7#comment-14114. I can work around it, but its annoying.

Is there a way to prevent IDs from incrementing upon each AJAX reload?

Thanks

Would be nice to get ajax submit documentation on here.

Hi guys,

I'm building my own custom field - and i am trying to get the field formatter using AJAX :

My field formatters has several fields including a button, which on click should
1/ Call a votingapi function to cast a voe
2/ Update a markup field in my page to take into account the new vote

My field formatter looks like this :

function vote_field_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  if ($display['type'] == 'vote_field_formatter_default') {
    list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
    $settings = $display['settings'];
    $values = array(
      'entity_type' => $entity_type,
      'entity_id' => $id,
      'tag' => $settings['tag'],
    );
    $element = array();
    $element[0] = drupal_get_form('vote_field_custom_widget', $values, $settings);
    return $element;
  }
}

Say i have the following fields in my form_builder function "vote_field_custom_widget":
  //I simplified the code here - Check if this is a form callback
  if(array_key_exists('triggering_element', $form_state)) {
     votingapi_set_vote(....);
  }
  $current_score = votingapi_get_scores(...);
  $form['score_display'] = array(
    '#type' => 'item',
    '#title' => t('Score'),
    '#markup' => check_plain($current_score),
    '#prefix' => '<div id="score-display-div">',
    '#suffix' => '</div>',
    );
  //Check if the user has ever voted for this entity
  $form['vote_up_button'] = array(
    '#type' => 'image_button',
    '#value' => t('Vote'),
    '#src' => drupal_get_path('module', 'vote_field') . '/images/up.png',
    '#ajax'=> array(
      'callback' => 'vote_field_vote_callback',
      'wrapper' => 'score-display-div',
      'method' => 'change',
      'effect' => 'fade',
    ),
  );

And my ajax callback looks like this :

function vote_field_vote_callback($form, $form_state) {
  return $form['score_display'];
}

The problem i have is that I think the AJAX will rebuild the form and the field formatter by calling vote_field_field_formatter_view, and hence, call the drupal_get_form. After checking at the drupal_get_form, i noticed that it creates a new $form and $form_state everytime so i don't have access to the $form_state[' triggering_element'] to check in my field_formatter function.

I am probably missing a step somewhere where i could have the new $form_state at the field formatter level ...

Anybody can help ?

Hi,
I created form that show additional textfields when you check checkbox (you can see it below).

My first question: I found it working only if I wrap and refresh whole form. How can I refresh only these two textfield without using special field set. I tried with markup but with no luck.

My second question: Value of checkbox is stored in v_email_smtp_server_auth variable. When I open again these form check box is already checked but folowing textfields are not show as ajax is no executed yet. How to resolve these?

$form['email']['v_email_smtp_server_auth'] = array(
  '#type' => 'checkbox',
  '#title' => t('Authentication required'),
  '#default_value' => variable_get('v_email_smtp_server_auth', 0),
  '#description' => t('Check these option if your server need login authentication.'),
  '#ajax' => array(
    'callback' => '_v_ajax_admin_settings_form_callback',
    'wrapper' => 'v-admin-settings-form',
    'effect' => 'fade',
    'progress' => array('type' => 'none'),
  ),
);
if (!empty($form_state['values']['v_email_smtp_server_auth']) && $form_state['values']['v_email_smtp_server_auth']) {
  $form['email']['v_email_smtp_username'] = array(
    '#type' => 'textfield',
    '#title' => t('Username'),
    '#default_value' => variable_get('v_email_smtp_username', ''),
    '#size' => 30,
    '#maxlength' => 50,
    '#required' => TRUE,
    '#description' => t('Username for SMTP server')
  );
  $form['email']['v_email_smtp_password'] = array(
    '#type' => 'password',
    '#title' => t('Password'),
    '#default_value' => variable_get('v_email_smtp_password', ''),
    '#size' => 30,
    '#maxlength' => 50,
    '#required' => TRUE,
    '#description' => t('Password for SMTP server')
  );
}

Thanks!

--
Aleš Curk :)
www.njorka.si

Drupal 7 in #type = password cannot have #default_value; how you solve this problem?

I believe that's exactly the snippet & quick explanation I been looking for, I'll give that a try to print "auto-updating" node edit forms (for each result returned in my draggable view), I have it working now using iframes but it's sooo stupid to bootstrap more then once like that to achieve multiple node edit forms on one page (view in my case). I'll let ya know if I get stuck, thanks for the tip yo.

There's another page discussing this here: https://drupal.org/node/348475

I tried "ajax_example" from examples-7.x-1.x-dev and i got the error.The error appears as a popup when I change a select option.

Firefox: An error occurred while attempting to process /drupal/en/system/ajax: this._each is not a function

Chrome: an error occurred while attempting to process /drupal/en/system/ajax: Object [object DOMWindow] has no method '_each'

I have no clue what it can be...

I can not even find what this AJAX-enabled Forms Example does. After installing and enabling, the module does not create a new content type, nor a new block, nor new content...

How do I even get started with this Ajax-form?

Thanks (and sorry for asking such a silly question ...)

I wouldn't expect to find a new content type or new block or anything like that. Look in the hook_menu() function in the Forms Example module and see what path the new form resides at. For example, I just opened the file form_example.module and can see this code:

<?php
  $items
= array();
 
$items['examples/form_example'] = array(
   
'title' => 'Form Example',
   
'page callback' => 'form_example_intro',
   
'access callback' => TRUE,
   
'expanded' => TRUE,
  );
?>

Which tells me that by going to http://www.example.com/examples/form_example I can see this particular function (form_example_intro) in action.

Thanks. Got it.

I have build a big ajax-multistep-form successfully with help from this ajax-example (Examples module).
On the last step is some validation.

What happens:

  • I am on the last step with incomplete inputs and than click "submit"
  • -> form_set_error() creates a typical Drupal-Errormessage.
  • I change nothing and click "back to last step"
  • -> form_set_error() creates a typical Drupal-Errormessage - but beyond the first one. There are now 2 messages.

The reason:

If you are inside the multiform any message produced by form_set_error() is placed inside the #ajax-div so it disappears after correcting the input at the next ajax-request.
BUT the last page has a classic submit Button - with no '#ajax'-Callbacks. This Button has a different behaviour.
In this case a message produced by form_set_error() is placed outside the #ajax-div because there is a real page-reload.

My question

What can I do to have only one place for error-messages ?
Because the submit ends with a drupal_goto(), this Button cannot be ajax. This would cause a big ajax-error: the return-value is not the expected $form.

Hi everyone, does anyone know how to integrate a hierarchical select inside a form_alter (in my case a user register) and make it work? In my case, the dropdowns don't react to each other and I've read it won't work unless I adapt it... but I couldn't read what 's the solution. Anyone?

thanks a lot

PIÑA&POLLO

A Javascript-Solution.

Idea: On "Submit" remove the error-msg above the FORM.
But: The default-event on AJAX-buttons is "mousedown" - not "click". I dislike this behaviour - and it's possible to change this in the form:

   '#ajax' => array(
       'wrapper' => 'wizard-form-wrapper',
       'callback' => 'ubg_multiform_wizard_callback',
       'event' => 'click', // not mousedown
   ),

Then this small js removes the error-msg if the user clicks on a prev/next Button:
(function ($) {
Drupal.behaviors.ubg_multiform = {
  attach: function (context) {
    $('input.form-submit.ajax-processed', context).click(function(){
      $('#content-header .messages').removeClass('messages error').empty();
    });
  }
};
})(jQuery);

Hi,
I tried your code which is in (In more detail) section. it worked correctly.

But I want to apply ajax on buttons, so I tweaked your code and instead of "select field", I used "textfield" to enter number of checkboxes, so that user can enter any number inside the textfield. but nothing happens when I click on "showbox" button.

please point out any wrong with the code.. or is there any example which implements this ?.

code:

<?php
function howmany_form($form, &$form_state) {
$form['howmany']['text'] = array(
       
'#title' => t('Enter text'),
       
'#type' => 'textfield',
       
'#size' => '1',
   
'#tree' => TRUE,
        );
 
$form ['button']    = array(
     
'#type' => 'submit',
     
'#value' => t('showbox'),
     
'#ajax' => array(
       
'event' => 'click',
       
'callback' => 'ajax_autocheckboxes_callback',
       
'wrapper' => 'checkboxes-div',
       
'method' => 'replace',
       ),
     );
 
$form['howmany_select'] = array(
   
'#type' => 'fieldset',
   
'#title' => t("Generated Checkboxes"),
   
'#prefix' => '<div id="checkboxes-div">',
   
'#suffix' => '</div>',
   
'#description' => t('This is where we get automatically generated checkboxes'),
  );
 
$num_checkboxes = !empty($form_state['values']['howmany']['text']) ? $form_state['values']['howmany']['text'] : 1;
  for (
$i=1; $i<=$num_checkboxes; $i++) {
   
$form['howmany_select']['checkboxes_fieldset']["checkbox$i"] = array(
     
'#type' => 'checkbox',
     
'#title' => "Checkbox $i",
    );
  }
 
$form['submit'] = array(
   
'#type' => 'submit',
   
'#value' => t('Submit'),
  );
  return
$form;
}
//ajax form call back function
function ajax_autocheckboxes_callback($form, $form_state) {
  return
$form['howmany_select'];
}
?>

Change is the only Constant

First off, for your 'showbox' button I would recommend '#type' => 'button' instead of '#type' => 'submit'. Then in your ajax_autocheckboxes_callback() callback you should be returning $form_state['values']['howmany_select'] to get the actual data entered by the user.

You should probably post general form questions like this in the forums.

Hi csdco,

Sorry for posting here.. thought if I post here all ajax related info will be at one place..

Now I created a forum for this. http://drupal.org/node/1579260

added '#type' => 'button' but still same problem..

and if i return the value $form_state['values']['howmany_select'], how the form gets refreshed with altered checkboxes..?

I want to use the textfield value to regenerate checkboxes with entire form refreshed.

please comment here.. http://drupal.org/node/1579260

Change is the only Constant

If you're returning the entire $form in your ajax callback because you've changed elements or added messages to update the user (or in a case I'm working on right now, setting $_SESSION variables that are used in different portions of the application), you must return a rebuilt form, not just the $form itself, or you can get some unexpected results. See this use case:

<?php
function example_ajax_form($form, &$form_state) {
 
$form = array(
   
'#prefix' => '<div id="example_form_wrapper">',
   
'#suffix' => '</div>',
  );
 
$form['select'] = array(
   
'#type' => 'select',
   
'#title' => 'Pick an Option',
   
'#options' => array('Red', 'Green', 'Blue'),
   
'#ajax' => array(
     
'callback' => 'example_ajax_form_process',
     
'wrapper' => 'example_form_wrapper',
    ),
  );
  if (isset(
$_SESSION['choice'])) {
   
drupal_set_message('You picked: ' . $form['select']['#options'][$_SESSION['choice']]);
  }
  return
$form;
}
function
example_ajax_form_process(&$form, &$form_state) {
  if (isset(
$form_state['values']['select']) && $form_state['values']['select'] != '_none') {
   
$_SESSION['choice'] = $form_state['values']['select'];
  }
 
// If we return $form and we visit this page anonymously, the first time we submit the form and pick an option *nothing* will happen.
 
return $form;
 
// If we return the rebuilt $form things will work as expected.
 
return drupal_rebuild_form('example_ajax_form', $form_state, $form);
}
?>

Does anyone has idea how this works on user registration form. Normally what i m doing using form_alter on user registration form added two fields a dropdown to select and textfields which are updated on the basis of selection from the dropdown with ajax.

But the problem is that after excecuting ajax on selection of dropdown the profile2 fields are lost from $edit in hook_user_insert() means any of profile2 fields value are not saved

Thanks in advance.

Mohit Sharma

http://www.mohitsharma.net

I have a custom multistep form that submits each step via ajax. It's working great if I use it as user 1. When I use it as another user, though, it seems to submit, and if I look at the "Net" tab in Firebug, it's even receiving the new form as it should, but for some reason the old form is not being replaced by the new one (the next step of the multi-step form). I can't figure it out.

I doubt it's a permissions thing because, like I said, it's receiving the new form according to Firebug, it's just not actually replacing it.

Anyone have any ideas?

I was trying to modify the ajax_example.module so i can validate value entered in the texfields. Below you'll find the code. But it seems that I can't access the field first name for example in oreder to validate it's value. I am still pretty new in drupal 7 module development so I am not quite sure that the approch I used below is the appropriate one. Thanks in advance for your help.

<?php
/**
* Show/hide textfields based on AJAX-enabled checkbox clicks.
*/
function ajax_example_autotextfields($form, &$form_state) {
 
$form['ask_first_name'] = array(
   
'#type' => 'checkbox',
   
'#title' => t('Ask me my first name'),
   
'#ajax' => array(
     
'callback' => 'ajax_example_autotextfields_callback',
     
'wrapper' => 'textfields',
     
'effect' => 'fade',
    )
  );
 
$form['ask_last_name'] = array(
  
'#type' => 'checkbox',
  
'#title' => t('Ask me my last name'),
   
'#ajax' => array(
     
'callback' => 'ajax_example_autotextfields_callback',
     
'wrapper' => 'textfields',
     
'effect' => 'fade',
    ),
  );
 
$form['textfields'] = array(
   
'#title' => t("Generated text fields for first and last name"),
   
'#prefix' => '<div id="textfields">',
   
'#suffix' => '</div>',
   
'#type' => 'fieldset',
   
'#description' => t('This is where we put automatically generated textfields'),
  );
 
// Since checkboxes return TRUE or FALSE, we have to check that
  // $form_state has been filled as well as what it contains.
 
if (!empty($form_state['values']['ask_first_name']) && $form_state['values']['ask_first_name']) {
   
$form['textfields']['first_name'] = array(
     
'#type' => 'textfield',
     
'#title' => t('First Name'),
    );
  }
  if (!empty(
$form_state['values']['ask_last_name']) && $form_state['values']['ask_last_name']) {
   
$form['textfields']['last_name'] = array(
     
'#type' => 'textfield',
     
'#title' => t('Last Name'),
    );
  }
 
$form['submit'] = array(
   
'#type' => 'submit',
   
'#value' => t('Click Me'),
  );
  return
$form;
}
/**
* Selects the piece of the form we want to use as replacement text and returns
* it as a form (renderable array).
*
* @return renderable array (the textfields element)
*/
function ajax_example_autotextfields_callback($form, $form_state) {
  return
$form['textfields'];
}
/**
* implementing hoo_validate for the form
*/
function ajax_example_autotextfields_validate($form, &$form_state) {
 
//$name = $form_state['values']['textfields']['first_name'];
 
if ($form_state['values']['textfields']['first_name'] == 'King Kong') {
   
form_set_error('first_name', t('Your own first name not allowed'));
  }
}
/**
* hook_submit
*/
function ajax_example_autotextfields_submit($form, &$form_state) {
 
$name = $form_state['values']['textfields']['first_name'];
 
drupal_set_message(t('Good Job, %name', array('%name' => $name)));
}
?>

the solution was to add '#tree' => 'fieldset'

Hi There,
I am running into exactly the same issue. And I cannot seem to fix it. Where in the code did you insert '#tree' => 'fieldset' to fix the issue?

Thanks,
RJ

I want to user ajax on select type. my test code is below.
I want to state dropdown depend on country value.

<?php
function hook_form_alter(&$form, $form_state, $form_id){
...
....
$form['field_test_country']['#ajax'] = array(
                 
'callback' => '_get_location_dropdown_callback',
                 
'wrapper' => 'state-dropdown-field-test-state',
                 
'method' => 'replace',
                   
'effect' => 'fade',
                 
'event' => 'change',
              );
$form['field_test_state']['#prefix'] = '<div id="state-dropdown-field-test-state">';
$form['field_test_state']['#suffix'] = '</div>';
....
...}
// ajax callback function
function _get_location_dropdown_callback($form, $form_state) {
    return
'testing';
}
?>

nothing happen.
please guide me how to solve this.
I am using latest drupal version. any help is appreciated.

Thank you.

Hello,

I have a node form with plenty field collection fields that have their labels altered.
When a user adds an element in a field collection, the form is processed and rebuilt as explained here and afterwards, it passes through my custom AHAH callback.

So, as more we add new elements in field collection fields, more form processing takes times... And so, it has an impact on performances

I was wondering what we can implement to reduce the impact of the form processing and rebuilding on performances.

I thought to speed up AHAH processing by:

  • Caching the form but as you can guess, it is a nightmare to manage it.
  • Bypassing the form processing but I think that has unwanted side effects on the node edition process.

Someone has an idea on the topic?

Here's some info on a related issue: http://drupal.stackexchange.com/questions/52051/slow-add-another-item-wi...

Basically, when dealing with large/complex node edit forms where the entire form is always rebuilt to include new #ajax elements, you can get very poor response times. I would recommend evaluating what you're currently doing and see if you can either:

or

  • Abandon the node entity type, or this particular node edit form, and build out your logic in a custom form where you either update your own table in the submit handler or update fields/properties on the original node.

#ajax with buttons work differently than rest of elements.
if you add #ajax attribute to buttons form builder function is not called.
you have to add '#executes_submit_callback' => FALSE, if you buttons work same as other elements.
otherwise submit function is called and than your callback. I had to spent few hours to debug that :/

I had an error where I had two sections that repeated on the same page.
Both had 'Add one' and 'Remove one' buttons, each calling to their own functions.

But when I clicked the first one, the second one would replace it's wrapper with the second sets contents.

I fixed this by having to change the '#value' field to have unique values.
They now repeat the correct fields.