How to manage ajax in nested forms? As implied in this question, I'm adding a list of similar child forms to my parent form with the following code:

foreach ($form_state['items'] as $key =&gt; $item) {

    $existing = NULL;
    if (isset($form['item_holder'][$key])) {
        $existing = $form['item_holder'][$key];
    }

    $state = NULL;
    if (isset($form_state['item_holder'][$key])) {
        $state = $form_state['item_holder'][$key];
    }

    $el = item_form_edit($existing, $state, $item);

    $form['item_holder'][$key] = $el;   
}


I am calling the form function directly because drupal_get_form() was causing errors due to confusion about which form was being submitted.

My child form type has ajax callbacks that return parts of it $form object. But  the child's callback function is receiving the parent form's object and causing an error trying to return parts of the child form.

How do I sort out ajax calls between parent and child $form contexts? Do I need to go back and add the child forms with drupal_get_form()? If so, how do I avoid confusing which form has been submitted?
It turns out Drupal will distinguish ajax for subforms automatically if you work within the system - which I was not.

Instead of calling the form builder function directly (bad), I use drupal_get_form() so the code above becomes:

foreach ($form_state['items'] as $key =&gt; $item) {

    $form['item_holder'][$key] = drupal_get_form('item_form_edit', $item);

}


I was previously loading the subitem's code with module_load_include(). I now load the sub-item's code with form_load_include() which should make a cached version of this form load correctly.

Since I am building a list of similar subforms, the subform needs to make sure it gets a unique wrapper:

function item_form_edit($form, &amp;$form_state, $edit = NULL) {

    $id_string = 'sub-item-form';
    $unique_id = drupal_html_id($id_string);    

    $form['#prefix'] = '&lt;div id="' . $unique_id . '"&gt;';
    $form['#suffix'] = '&lt;/div&gt;';

    ...

    return $form;
}


Now, an AJAX element on the subform can replace that subform with 

    '#ajax' =&gt; array(
        'wrapper' =&gt; $unique_id,
        'callback' =&gt; 'subform_callback',
        ...


In this example, the entire subform is being replaced by the callback:

function subform_callback($form, &amp;$form_state) {
    return $form;
}


My subform builder function is in a separate file, so hook_init() needs to make Drupal aware of the subform code during AJAX requests:

if ($_GET['q'] == 'system/ajax' || strstr($_GET['q'], 'file/ajax/')) {
    if (preg_match('/item_form_edit/', $_POST['form_id'])) {
        module_load_include('inc', 'mymodule', 'file_with_item_form');
    }
}