#ajax elements added in hook_form_alter miss after first ajax call I am modifying elements from the multiselect module to add ajax functionality. I wanted to use hook_field_widget_WIDGET_TYPE_form_alter() but I'm stuck in 7.14 and it requires 7.8.

So, I'm traversing the $form in hook_form_alter() to find the modify the 'multiselect' elements:

/*
 * Implements hook_form_alter()
 */
function ajax_multiselect_form_alter(&amp;$form, &amp;$form_state, $form_id) {
  _ajax_multiselect_search_children($form, $form);
}

/*
 * Look for multiselect elements
 */
function _ajax_multiselect_search_children(&amp;$form, &amp;$element) {

  if (isset($element['#type']) &amp;&amp; $element['#type'] == 'multiselect') {
    _ajax_multiselect_modify_multiselect($form, $element);
  }

  $children = element_children($element);

  if (is_array($children)) {
    foreach ($children as $child) {
      _ajax_multiselect_search_children($form, $element[$child]);
    }
  }
}


When I find a 'multiselect' element, I add a new 'select' element to the form with the #ajax property copied from the original 'multiselect'. 

/*
 * Modify the multiselect for ajax processing
 */
function _ajax_multiselect_modify_multiselect(&amp;$form, &amp;$element) {

  $element['#attached']['js'] = array(
    array(
      'data' =&gt; drupal_get_path('module', 'ajax_multiselect') . '/js/ajax_multiselect.js',
    ),
  );


  if (isset($element['#ajax'])) {

    $ajax_element_id = drupal_html_id('ajax_multiselect_element');

    // tell jquery where to find the id of the dummy select
    $element['#attributes']['class'][] = 'multiselect-element-id-holder';
    // transmit the id of the dummy select to jquery
    $element['#attributes']['data-ajax-multiselect-element-id'] = $ajax_element_id;

    $form[$ajax_element_id] = array(

      '#id' =&gt; $ajax_element_id,
      '#type' =&gt; 'select',
      '#ajax' =&gt; $element['#ajax'],
      '#options' =&gt; array(0,1),

//      '#prefix' =&gt; '&lt;div style="display:none"&gt;',
//      '#suffix' =&gt; '&lt;/div&gt;',
    );

  }

}


Then, in Javascript, I trigger a 'change' event on the new (dummy) 'select' whenever the items in the 'multiselect' are altered.

  // create a new function that incorporates the old function to add/remove options in multiselect
  $.fn.oldAddOption = $.fn.addOption;
  $.fn.addOption = function(arguments) {
    this.oldAddOption(arguments);

    // find the tag that holds the id of the ajax multiselect element
    var tag_with_id = $(this).parent().parent().find('.multiselect-element-id-holder');
    // find the id of the ajax multiselect element
    var ajax_element_id = tag_with_id.data('ajax-multiselect-element-id');

    $('#'+ajax_element_id).trigger('change');
  }


This works for the first #ajax round trip, but after the first #ajax call anywhere on the page, my new (dummy) 'select' elements don't fire the correct #ajax.  In my Drupal Recent Logs, I get

Undefined index: #ajax in ajax_form_callback() 


when I use the dummy select elements. 

In network activity, I can see that the first #ajax response includes the correct array of commands for the replace action. But, after the first #ajax anywhere on the form, my new 'select' elements only receive a default #ajax settings response with no replace commands.

I think there is something about the way I am building in hook_form_alter that is not adding the #ajax property correctly after the first ajax call, but I can't figure out what it is.
The problem was relying on the IDs created by drupal_html_id() to match after ajax rebuild of the form. I fixed it by having jQuery find the dummy select elements by 'name' attribute.

  $.fn.oldAddOption = $.fn.addOption;
  $.fn.addOption = function(arguments) {
    this.oldAddOption(arguments);

    // find the tag that holds the id of the ajax multiselect element
    var tag_with_name = $(this).parent().parent().find('.multiselect-element-name-holder');
    // find the id of the ajax multiselect element
    var ajax_element_name = tag_with_name.data('ajax-multiselect-element-name');

    $('select[name="'+ajax_element_name+'"]').trigger('change');
  }


This code now sets unique element names instead of trying to set unique ids:

$ajax_element_name = drupal_html_id('ajax-multiselect-element');

// tell jquery where to find the id of the dummy select
$element['#attributes']['class'][] = 'multiselect-element-name-holder';
// transmit the id of the dummy select to jquery
$element['#attributes']['data-ajax-multiselect-element-name'] = $ajax_element_name;

$form[$ajax_element_name] = array(
  '#type' =&gt; 'select',
  '#ajax' =&gt; $element['#ajax'],
  '#options' =&gt; array(0,1),
);