I'm using my theme's form_alter function to ajaxify a select dropdown field on my node add/edit form. When the ajax is triggered, my callback function enables/disables other elements on the form and then replaces elements in others with ajax_command_replace (the values of which then get set in the alter function itself after checking if form_state['values'] has been set).

Here's what I do:

  1. I enter values into the form.
  2. I select a value in the field which triggers the ajax.
  3. I submit the form.

The problem: the other select elements in the form that were set before the ajax trigger do not have the values I had set them to.

I have about 15 total fields in the form, a mix between selects and text fields. Do I need to check the form_state['values'] array for every field and reassign each element's default_value in the alter function?

I'm not even sure if my approach is correct... Maybe I am just missing something very simple. Any advice is appreciated. Here is my code:

function asset_form_alter_callback (&$form, $form_state) {
  $commands = array();
  $nid = $form_state['values']['field_asset_group']['und'][0]['target_id'];
  $node = node_load($nid);

  if($node->field_asset_type['und'][0]['value'] == 'group') {
      $commands[] = ajax_command_invoke('#edit-field-manufacturer select', 'attr', array('disabled','disabled'));
      $commands[] = ajax_command_invoke('#edit-field-manufacturer .form-item', 'addClass', array('form-disabled'));
      $commands[] = ajax_command_invoke('#edit-field-model input', 'attr', array('disabled','disabled'));
      $commands[] = ajax_command_invoke('#edit-field-model .form-item', 'addClass', array('form-disabled'));
      $commands[] = ajax_command_invoke('#edit-field-serial input', 'attr', array('disabled','disabled'));
      $commands[] = ajax_command_invoke('#edit-field-serial .form-item', 'addClass', array('form-disabled'));
      $commands[] = ajax_command_invoke('#edit-field-life-expectancy input', 'attr', array('disabled','disabled'));
      $commands[] = ajax_command_invoke('#edit-field-life-expectancy .form-item', 'addClass', array('form-disabled'));
      $commands[] = ajax_command_invoke('#edit-field-original-cost input', 'attr', array('disabled','disabled'));
      $commands[] = ajax_command_invoke('#edit-field-original-cost .form-item', 'addClass', array('form-disabled'));

  } else {
    if($node->field_asset_type['und'][0]['value'] == 'serialized') {
      $commands[] = ajax_command_invoke('#edit-field-manufacturer select', 'removeAttr', array('disabled'));
      $commands[] = ajax_command_invoke('#edit-field-manufacturer .form-item', 'removeClass', array('form-disabled'));
      $commands[] = ajax_command_invoke('#edit-field-model input', 'removeAttr', array('disabled'));
      $commands[] = ajax_command_invoke('#edit-field-model .form-item', 'removeClass', array('form-disabled'));
      $commands[] = ajax_command_invoke('#edit-field-serial input', 'removeAttr', array('disabled'));
      $commands[] = ajax_command_invoke('#edit-field-serial .form-item', 'removeClass', array('form-disabled'));
      $commands[] = ajax_command_invoke('#edit-field-life-expectancy input', 'removeAttr', array('disabled'));
      $commands[] = ajax_command_invoke('#edit-field-life-expectancy .form-item', 'removeClass', array('form-disabled'));
      $commands[] = ajax_command_invoke('#edit-field-original-cost input', 'removeAttr', array('disabled'));
      $commands[] = ajax_command_invoke('#edit-field-original-cost .form-item', 'removeClass', array('form-disabled'));         
    }
  }
  $commands[] = ajax_command_replace('.form-field-name-field-attributes-collection', drupal_render($form['field_attributes_collection']));
  return array('#type' => 'ajax', '#commands' => $commands);
}

function fmdatatool_form_alter(&$form, &$form_state, $form_id) {

  if ($form_id == 'asset_node_form') {  

    $form['field_asset_group']['und']['#ajax'] = array(
      'callback' => 'asset_form_alter_callback',
      'effect' => 'fade',
      'wrapper' => 'replace-form'
    );

    if ((isset($form_state['values']['field_asset_group']['und'][0]['target_id'])) || ((!(empty($form_state['triggering_element']['#name']))) && (preg_match("/remove_button|upload_button|add_more/", $form_state['triggering_element']['#name'])))) {

      if (isset($form_state['values']['field_asset_group']['und'][0]['target_id'])) {
        $form['field_asset_group']['und']['#default_value'][0] = $form_state['values']['field_asset_group']['und'][0]['target_id'];
        $form['field_asset_group']['und']['#entity']->field_asset_group['und'][0]['target_id'] = $form_state['values']['field_asset_group']['und'][0]['target_id'];
      }

      $nid = $form['field_asset_group']['und']['#default_value'][0];
      $node = node_load($nid);

      $view = views_get_view('attributes');
      $view->set_display('entityreference_1');
      $view->init_handlers();
      $view->preview('entityreference_1', array($form['field_asset_group']['und']['#default_value'][0]));
      $views_array = array();
      $views_array['_none'] = ' - None - ';
      foreach ($view->result as $res) {
        if (isset($res->field_body[0]['rendered']['#markup'])) {
          $views_array[$res->nid] = $res->node_title . " - " . $res->field_body[0]['rendered']['#markup'];
        } else {
          $views_array[$res->nid] = $res->node_title;
        }
      }
      foreach ($form['field_attributes_collection']['und'] as $key => $fc_mycollection) {
        if (is_numeric($key)) {
          $form['field_attributes_collection']['und'][$key]['field_attributes']['und']['#options'] = $views_array;
        }
      }
    }
  }

}

EDIT:

I experimented with the DFV module per a suggestion below and unfortunately it doesn't work with field collections, which the last part of my code populates in my form (field_attributes_collection). I also enable/disable fields depending upon the value of other fields (which Conditional Fields can accommodate, but not with dynamic field values), so it would have been nice if DFV and Conditional Fields played well together. However, it was good to look at the DFV module though because it showed me my code was relatively correct. There was one particular field I was having trouble with (getting the dreaded "An illegal choice has been detected" (Resolve the error "An illegal choice has been detected...") and I just had to repopulate that field in my form_alter function based on if a value was set in $form_state.

  • Why writing custom code? Have you checked the Conditional Fields module? "Conditional Fields allows you to manage sets of dependencies between fields. When a field is “dependent”, it will only be available for editing and displayed if the state of the “dependee” field matches the right condition." – user1527576 Aug 16 '15 at 1:05
  • I do use the Conditional Fields module already - unfortunately the matching of the "right condition" and the values in the field are based on the value of another field, which is dynamically populated. The Conditional Fields module can't do that at this point, hence the custom code. – hawkeye217 Aug 16 '15 at 1:48
  • First: For the entityreference select which is dependent on the first entityreference select, you could use the DFV module (see my answer on another question here) it's tested and it works very well nad you have less code to maintain Second: are you replacing the entire form, at the end of the callback? This could be a problem, I would replace the single element, not the entire form – user1527576 Aug 16 '15 at 10:19
  • I edited my post above based on your suggestion of the DFV module. As far as replacing the entire form in the callback, this page (drupal.org/node/752056) says that returning a portion of (or the whole form for that matter) isn't necessary. The ajax callback can return any renderable array or an HTML string. The AJAX examples in the Examples module are doing exactly what my code above does, so I think I'm on the right track. – hawkeye217 Aug 16 '15 at 13:46
  • I'm glad that it was somewhat helpful! Maybe I should better explain my second point in my previous comment: probably this is what's happening: you change values in the form's "normal" fields. Then you change the ajax fields and the form gets entirely reloaded. This operations, since you're replacing the complete form, wipes the information you've entered in the "normal" fields (I don't see that you're reading that info and populating again the values after replacing the form). By replacing only the specific elements this problem should be resolved. – user1527576 Aug 16 '15 at 17:17

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Browse other questions tagged or ask your own question.