Aug 27, 2012

Posted by in Drupal | 18 comments

How to use Drupal AJAX form for multiple fields with add more concept.

Back to writting after a long time. I have been working with Drupal extensively these days and had a need where I had to use Drupal AHAH Form, Currently known as Drupal AJAX Form in Drupal 7.

If you download the set of examples that drupal provides, it gives you an example of drupal ajax form with add more button, where we can manipulate only one field.

In this POST, I will teach you how you can use the same concept to manipulate more than one field.

Here is an example.

function modulename_add_more_form()
{
    $form['description'] = array(
    '#markup' => '<div>This is an example of a AJAX Form, where we can use AJAX add more concept in drupal for a set of fields.</div>',
  );

  // Because we have many fields with the same values, we have to set
  // #tree to be able to access them.
  $form['#tree'] = TRUE;
  $form['names_fieldset'] = array(
    '#type' => 'fieldset',
    '#title' => t('Family member details'),
    // Set up the wrapper so that AJAX will be able to replace the fieldset.
    '#prefix' => '<div id="names-fieldset-wrapper">',
    '#suffix' => '</div>',
  );

  // Build the fieldset with the proper number of names. We'll use
  // $form_state['num_names'] to determine the number of textfields to build.
  if (empty($form_state['num_names'])) {
    $form_state['num_names'] = 1;
  }
 
  for ($i = 0; $i < $form_state['num_names']; $i++) {
   
    //lets add all the fields we want in the set  
    /*
    We have the prefix and suffix added here, so that we can do some sort of styling with the form, like display the fields side by side. You may remove    it, but generally we need that when we have a set of fields, hence I thought to keep it here.
    */

   
    //Parent container
    $form['names_fieldset'][$i] = array(
    '#prefix' => '<div class="two-col">',
    '#suffix' => '</div>'
    );
   
    //other form elements
    $form['names_fieldset'][$i]['firstname'] = array(
      '#type' => 'textfield',
      '#title' => t('First Name'),
      '#prefix' => '<div class="col1">',
      '#suffix' => '</div>'
    );
   
    $form['names_fieldset'][$i]['lastname'] = array(
      '#type' => 'textfield',
      '#title' => t('Last Name'),
      '#prefix' => '<div class="col2">',
      '#suffix' => '</div>'  
    ); 
   
    //-- Like wise we can add more
  }
 
  $form['names_fieldset']['add_name'] = array(
    '#type' => 'submit',
    '#value' => t('Add one more'),
    '#submit' => array('modulename_add_more_add_one'),
    // See the examples in ajax_example.module for more details on the
    // properties of #ajax.
    '#ajax' => array(
      'callback' => 'modulename_add_more_callback',
      'wrapper' => 'names-fieldset-wrapper',
    ),
  );
 
  if ($form_state['num_names'] > 1) {
    $form['names_fieldset']['remove_name'] = array(
      '#type' => 'submit',
      '#value' => t('Remove one'),
      '#submit' => array('modulename_add_more_remove_one'),
      '#ajax' => array(
        'callback' => 'modulename_add_more_callback',
        'wrapper' => 'names-fieldset-wrapper',
      ),
    );
  }
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Submit'),
  );

  return $form;

}

/**
 * Callback for both ajax-enabled buttons.
 *
 * Selects and returns the fieldset with the names in it.
 */

function modulename_add_more_callback($form, $form_state) {
  return $form['names_fieldset'];
}

/**
 * Submit handler for the "add-one-more" button.
 *
 * Increments the max counter and causes a rebuild.
 */

function modulename_add_more_add_one($form, &$form_state) {
  $form_state['num_names']++;
  $form_state['rebuild'] = TRUE;
}

/**
 * Submit handler for the "remove one" button.
 *
 * Decrements the max counter and causes a form rebuild.
 */

function modulename_add_more_remove_one($form, &$form_state) {
  if ($form_state['num_names'] > 1) {
    $form_state['num_names']--;
  }
  $form_state['rebuild'] = TRUE;
}

/**
 * Final submit handler.
 *
 * Reports what values were finally set.
 */

function modulename_add_more_submit($form, &$form_state) {
 
  //Process the data of form here and use it
 
  /*
  #Example usage
  $form_state['input']['name_fieldset'][0,1,2... index number]['fieldname'];
 
  you can always use print_r($form_state); to explore the submited data.
  */

}
  1. This is a great example, thank you for sharing. The only issue I had was in the AJAX method. The default method is “replaceWith”, so it appeared as if the code wasn’t working (it didn’t create a new field set). By adding ‘method’ => ‘append’, to the ajax array in $form[‘names_fieldset’][‘add_name’] I was able to get the new field to appear.
    -p

  2. Hi,
    I am working on bringing multiple fields using ajax. I followed your code every thing works fine.. But the index value is not incremental.. Please help me to overcome from this issue.

  3. thanks for the response,

    As you mentioned in you example

    $form_state[‘input’][‘name_fieldset’][0,1,2… index number]

    in this index. I am getting only the 0th element.

    I think “modulename_add_more_callback” makes a copy from existing fieldset and returning it into form.

    Even I removed “modulename_add_more_add_one” function the fields get adding. and if i changed the increment value to 2 it wont replicate.

    So is there any other thing that i ve to add other than this code.?

    • did you try print_r($form_state); to see what all values are coming, I had used the same example in my keyword_highlighter module if you see that and it is working fine.

  4. ya i looked it into your and i used it into my module also, it’s works fine.. but when i copied your form into my module the same issue is raising. I was rendered my form into the template. Is that a problem..?

    • hmm not sure.. if yours is an independent module, you may zip the module code and send it to me so that I can look at it myself. dharam(dot)new(at)gmail(dot)com is my email id.

  5. thanks,

    when i click add more, the complete page is reloading whereas for you it’s not happening. What i’ve to do to fix that issue.

  6. Mujtaba Ahmad says:

    Same problem all the form is being validated. and $form_state[‘num_names’] remains 1, don’t know why

  7. Hi Dharam,
    Good for the tutorial, but you missed one thing. hook_form need 3 variable to be passed form, form_state and form_id. And works great!
    ;-)

  8. I found one issue in code. Form function must be :
    function modulename_add_more_form($form, &$form_state)
    {
    …..

  9. Just replace modulename_add_more_form() function by modulename_add_more_form($form, &$form_state)

  10. I struggled for 2 hours and figured it out.. in my case, in the place of modulename in the code snippet it actally had to be the form name.

    for example, my module name : godown ,and
    my form name : godown_item_form

    all along the way i was replacing the modulename in the code with godown(my module’s name) but when i replced it with godown_item_form(my form’s name) it started working like a charm…. :) hope this helps

  11. Guillaume says:

    Hello,

    It’s works with function modulename_add_more_form($form,$form_states)

  12. Looks good :), but how it would be in the custom widget, for example textfield?

    thx

  13. Nice one, thx a lot

  14. Hi Dharam,
    I am new to Drupal so forgive me if this question seems silly. I would like to know where to place this code in order to have it working with the webfrom module. ie where do i place this code to get the field set to show up when creating webforms.

Leave a Reply