I am following the ajax_example.module in the example module closely. Essentially, I have a fieldset with several fields inside. The user fills out these fields, clicks 'add more', and then another fieldset loads beneath it via AJAX.
My form works fine for up to three entries. But, after a third entry is added, it begins duplicating fieldsets.
The logic that generates the form is a simple for loop; it should work the same for 1 or 100 values, and I'm not really sure why the duplicates are being generated. What's even more perplexing is that if I examine $form in a debugger, the form elements are all where they should be, and there are no duplicates.
Code overview: I have a page that calls this form. The form has a button with the 'ajax' property, and when clicked, it adds 1 to $form_state['item_quantity']. Then, it regenerates the form, and a for loop creates one fieldset per item_quantity. There is a conditional to check if this is the last item, which will add a special CSS class if true.
function manual_import_form($form, &$form_state) {
//set up options for select list
$task_options = get_task_options();
$location_options = get_location_options();
$model_options = get_model_options();
$form['#attached'] = array(
'css' => array(
'type' => 'file',
'data' => drupal_get_path('module','manual_import') . '/manual_import.css',
),
);
$form['#tree'] = TRUE;
$form['scenario'] = array(
'#type' => 'select',
'#title' => t('Import Scenario'),
'#options' => array(
'shipment' => t('Shipment'),
'location' => t('Location'),
'manual' => t('Manual'),
),
'#default_value' => 'shipment',
);
$form['scenario_shipment'] = array(
'#type' => 'fieldset',
'#title' => t('Associate Group To Shipment'),
'#description' => t('Associate a group of items to a shipment, and auto-generate tasks'),
'#states' => array(
'visible' => array(
':input[name="scenario"]' => array('value' => 'shipment'),
),
),
'#collapsible' => TRUE,
'#collasped' => FALSE,
);
$form['scenario_shipment']['shipping_list_number'] = array(
'#type' => 'textfield',
'#title' => t('Shipping List Number'),
'#prefix' => '<div class="manual-import-shipping-list">',
'#suffix' => '</div>',
);
$form['scenario_shipment']['shipping_from'] = array(
'#type' => 'select',
'#title' => t('Shipping From'),
'#options' => $location_options,
'#default_value' => 283,
);
$form['scenario_shipment']['shipping_to'] = array(
'#type' => 'select',
'#title' => t('Shipping To'),
'#options' => $location_options,
'#default_value' => 283,
);
$form['scenario_location'] = array(
'#type' => 'fieldset',
'#title' => t('Associate Group To Location'),
'#description' => t('Associate a group of items to a location, and auto-generate tasks'),
'#states' => array(
'visible' => array(
':input[name="scenario"]' => array('value' => 'location'),
),
),
'#collapsible' => TRUE,
'#collasped' => FALSE,
);
$form['scenario_location']['location'] = array(
'#type' => 'select',
'#title' => t('Location'),
'#options' => $location_options,
'#default_value' => 283,
);
$form['scenario_manual'] = array(
'#type' => 'fieldset',
'#title' => t('Manually Create Tasks'),
'#description' => t('Manually select the tasks to be created for the items in the group.'),
'#states' => array(
'visible' => array(
':input[name="scenario"]' => array('value' => 'manual'),
),
),
'#collapsible' => TRUE,
'#collasped' => FALSE,
);
$form['scenario_manual']['task'] = array(
'#type' => 'select',
'#title' => t('Task Type'),
'#options' => $task_options,
);
$form['import_items'] = array(
'#type' => 'container',
'#prefix' => '<div id="import_items">',
'#suffix' => '</div>',
);
if (empty($form_state['import_item_quantity'])) {
$form_state['import_item_quantity'] = 1;
}
for ($i = 1; $i <= $form_state['import_item_quantity']; $i++) {
$form['import_items'][$i] = array(
'#type' => 'fieldset',
'#title' => t('Import Item @item', array('@item' => $i)),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
);
$form['import_items'][$i]['ticket_number'] = array(
'#type' => 'textfield',
'#maxlength' => 32,
'#title' => t('Ticket Number'),
'#class' => 'manual-import-item-field',
'#prefix' => '<div class="manual-import-item-field manual-import-item-ticket">',
'#suffix' => '</div>',
);
$form['import_items'][$i]['device_id'] = array(
'#type' => 'textfield',
'#maxlength' => 32,
'#title' => t('Device ID'),
'#prefix' => '<div class="manual-import-item-field manual-import-item-device-id">',
'#suffix' => '</div>',
);
$form['import_items'][$i]['device_model'] = array(
'#type' => 'select',
'#title' => t('Make/Model'),
'#options' => $model_options,
'#prefix' => '<div class="manual-import-item-field manual-import-item-device>',
'#suffix' => '</div>',
);
if ($i == $form_state['import_item_quantity']) {
$form['import_items'][$i]['device_model']['#prefix'] =
'<div class="manual-import-item-field manual-import-item-device manual-import-item-last">';
}
}
$form['import_items']['item_add'] = array(
'#type' => 'submit',
'#value' => 'Add another!',
'#ajax' => array(
'callback' => 'manual_import_item_ajax_callback',
'wrapper' => 'import_items',
),
'#submit' => array('manual_import_item_add'),
);
xdebug_break();
return $form;
}
function manual_import_item_ajax_callback($form, $form_state) {
return $form['import_items'];
}
function manual_import_item_add($form, &$form_state) {
$form_state['import_item_quantity']++;
$form_state['rebuild'] = TRUE;
}