I have built a custom CCK field type that stores 2 columns. hook_widget() returns an $element with 2 form elements, the 2nd of which is blank until the value of the first element is chosen. I cannot figure out how to add the data into the 2nd element via #ahah and have the form rebuilt so that I don't receive validation errors (because the #options for element #2 didn't exist when the widget was initially built). Can this be achieved in a CCK widget? I know I've seen this elsewhere, i.e. hierarchical select in D6 or addressfield module in D7 (this current task is D6 unfortunately).

My widget and #ahah callback is currently:

<?php
/**
 * Implementation of hook_widget().
 */
function custom_cck_product_upgrades_widget(&$form, &$form_state, $field, $items, $delta = 0) {
  // Generate a unique ID for this product upgrades wrapper.
  $product_upgrades_wrapper_id = implode('_', array($field['field_name'], $delta));

  $element['#type'] = 'fieldset';
  $element['#title'] = 'Product Upgrades';
  $element['#collapsible'] = TRUE;

  $element['product'] = array(
    '#title' => 'Product',
    '#type' => 'select',
    '#options' => array('- Select -') + _custom_cck_product_upgrades_get_products(),
    '#default_value' => isset($items[$delta]['product']) ? $items[$delta]['product'] : NULL,
    '#ahah' => array(
      'path' => 'custom-cck-product-upgrades/ajax/product-upgrades',
      'wrapper' => $product_upgrades_wrapper_id,
      'method' => 'replace',
      'effect' => 'fade',
    ),
  );

  $element['value'] = array(
    '#title' => 'Product Upgrades',
    '#type' => 'checkboxes',
    '#default_value' => isset($items[$delta]['value']) ? $items[$delta]['value'] : NULL,
    '#prefix' => "<div id='{$product_upgrades_wrapper_id}'>",
    '#suffix' => "</div>",
  );

  // Get all upgrade options for the current product.
  if (isset($items[$delta]['product'])) {
    $options = array();
    $result = db_query("SELECT * FROM {custom_products} WHERE product_family = %d", $items[$delta]['product']);
    while ($row = db_fetch_array($result)) {
      $options[$row['id']] = $row['name'];
    }
    $element['value']['#options'] = $options;
  }

  return $element;
}

function custom_cck_product_upgrades_widget_ahah($form, $form_state) {
  // Load the form from the cache.
  $form_state = array('storage' => NULL, 'submitted' => FALSE);
  $form_build_id = $_POST['form_build_id'];
  $form = form_get_cache($form_build_id, $form_state);

  $form['#programmed'] = $form['#redirect'] = FALSE;

  $form = form_builder($form['form_id']['#value'], $form, $form_state);
  $form_state['values'] = $form['#post'] = $_POST;
  form_set_cache($form_build_id, $form, $form_state);

  // I can rebuild the element here, but it makes no difference because the original form doesn't know about this...
  $element = array();

  $output = theme('status_messages') . drupal_render($element);

  return drupal_json(array('status' => TRUE, 'data' => $output));
}
?>