Found the answer to my issue in #1764350-6: Form rebuild overwrites selected values but it really wasn't related enough to post on that thread.

I've built a custom form using and my _submit contains:

$form_state['rebuild'] = TRUE; // needed to pass $form_state back to _form function

When I submit, all the other fields preserve their inputed values (which is what I want because they are filters for table, so people want to keep what they've filtered by). But the HS field was losing it's value. It came through in $form_state['values'] but for some reason #default_value wasn't being respected.

Tracked it down to this chunk of code in the hierarchical_select.module:

function form_hierarchical_select_process($element, &$form_state, $complete_form) {
  ...
  // This prevents values from in $form_state['input'] to be used instead of
  // the generated default values (#default_value).
  // For example: $element['hierarchical_select']['selects']['0']['#default_value']
  // is set to 'label_0' after an "Add" operation. When $form_state['input']
  // is NOT erased, the corresponding value in $form_state['input'] will be
  // used instead of the default value that was set. This would result in
  // undesired behavior.
  drupal_array_set_nested_value($form_state['input'], $element['#array_parents'], array());
  ...
}

That would do it!

So I used the other issue to add two #process callbacks to my HS form element:

$form['my_hs'] = array(
    '#type' => 'hierarchical_select',
    '#title' => t('My HS'),
    '#size' => 1,
    '#config' => array(
      'module' => 'hs_taxonomy',
      ...
    ),
    '#process' => array(
      // Add our process function before the original process function
      // so we can preserve the form_state[input] before HS deletes it
      'MODULE_preserve_hierarchicalselect_input',
      'form_hierarchical_select_process',
      'MODULE_restore_hierarchicalselect_input',
    ),
  );

Then those functions are pretty dead-simple, just working around by saving and restoring:

/**
 * Hierarchical select form element type #process callbacks
 * 
 * These are needed because HS overwrites the #default_value so we have to wrap
 * it's processing to preserve, then restore, otherwise the value isn't kept
 * when the form reloads.
 * 
 * See line 808 in hierarchical_select.module for what we're working to avoid.
 */
function MODULE_preserve_hierarchicalselect_input($element, &$form_state, $complete_form) {
  $element['#preserve_input'] = $form_state['input']['my_hs'];
  return $element;
}

function MODULE_restore_hierarchicalselect_input($element, &$form_state, $complete_form) {
  drupal_array_set_nested_value($form_state['input'], $element['#array_parents'], $element['#preserve_input']);
  return $element;
}

Comments

spcalpo’s picture

I've tried this solution and (with some tweaking for my use case; I was crazy enough to want an 'add more' ajax functionality with hierarchical_select) seems like it's working as desired. Thank you for sharing, covenantd. :)

I have made a lot of use of hierarchical_select in recent projects. Makes me wish I had more time to help maintain it, as it is a very useful module with some quirks that have set me back for days here and there.