1

My dynamic Competition form has two basic parts:

1- Basic Info

  • Name
  • Size Dropdown

2- Ajax Fields

  • Options dropdown based on Size

When I change the value in Size, a new combobox is loaded via AJAX with related values.

Here is part of my form:

if ($competition->size == 0)
    {
        $form['country'] = array(
            '#type' => 'select',
            '#title' => t('Country'),
            '#weight' =>3,
            '#required' => FALSE,
            '#zurb_class'=> 'cleared',
            '#default_value' => $competition->country_id,
            '#options' => _ajax_countries_dropdown_options(),
            '#prefix' => '<div id="dropdown-competition-size-replace">',
            '#suffix' => '</div>',
        );
    }
    else if ($competition->size == 1)
    {
        $form['continent'] = array(
            '#type' => 'select',
            '#title' => t('Continent'),
            '#default_value' => $competition->continent_id,
            '#weight' =>2,
            '#required' => FALSE,
            '#options' => _ajax_continents_dropdown_options(),
            '#prefix' => '<div id="dropdown-competition-size-replace">',
            '#suffix' => '</div>',

        );
    }
    else
    {
        $suffix = '<div id="dropdown-competition-size-replace"></div>';
    }

    $form['size'] = array(
        '#type' => 'select',
        '#title' => t('Size'),
        '#default_value' => $competition->size,
        '#weight' =>1,
        '#options' => $options_size,
        '#required' => FALSE,
        '#ajax' => array(
            'callback' => 'ajax_competition_size_dropdown_callback',
            'wrapper' => 'dropdown-competition-size-replace',
            'method' => 'replace',
            'effect' => 'fade',
        ),
        '#suffix' => $suffix,
    );

Ajax Callback

function ajax_competition_size_dropdown_callback($form, $form_state) {
    $size = $form_state['values']['size'];

    if ($size == 0)
    {
        return array(
            '#name' => 'country',
            '#type' => 'select',
            '#title' => t('Country'),
            '#weight' =>3,
            '#required' => FALSE,
            '#zurb_class'=> 'cleared',
            '#default_value' => $competition->country_id,
            '#options' => _ajax_countries_dropdown_options(),
            '#prefix' => '<div id="dropdown-competition-size-replace">',
            '#suffix' => '</div>',
        );
    }
    else if ($size == 1)
    {
        return array(
            '#name' => 'continent',
            '#type' => 'select',
            '#title' => t('Continent'),
            '#default_value' => $competition->continent_id,
            '#weight' =>2,
            '#required' => FALSE,
            '#options' => _ajax_continents_dropdown_options(),
            '#prefix' => '<div id="dropdown-competition-size-replace">',
            '#suffix' => '</div>',
        );
    }
    else
    {
        return '<div id="dropdown-competition-size-replace"></div>';
    }
}

Steps I made so far:

  • When I change the first select when editing, the values are not saved.
  • Debugging Backend
  • The form changes on the front (AJAX), but it does not change on the backend
  • Apparently the problem is I am creating the form fields based on size, Drupal will only recognize this fields. So when I change the select and load the second, it won't parsed by Drupal
  • I tried to use $form_state['rebuild'] = TRUE; but it didn't fix anything, actually avoided the redirection after submission.
1

The Ajax callback should only return the named FAPI element that is to be replaced. For example:

function questionaire_4D_selector_form_ajax_callback($form, $form_state) {
  // If the form has errors we show them in the Preview spot. There's not much
  // else we can do because jQuery is replacing out the specified
  // target element in the #ajax FAPI element.
  if (form_get_errors()) {
    return $form['preview-content-area']['esci-questionaire'];
  }
  return $form['preview-content-area']['esci-questionaire'];
}

Your form_builder function which build/rebuilds the form should examine the $form_state and alter the form as necessary based on the ajax submitted values:

/** Our form builder function */
function questionaire_4d_selector_form($form, &$form_state) {
 # for ajax inspection goto /tmp and view file output.
 #dd($form_state);
 #dpm($form_state);

  // This form responds to an AJAX submit button, and also a $_GET argument.
  $form_passed_get_parameter_questionaire_id = $form_state['submitted'] == FALSE &&
          count($form_state['build_info']['args']) &&
          ctype_digit($form_state['build_info']['args'][0]);
  #dpm($form_passed_get_parameter_questionaire_id ? 1 : 0);
  if ($form_passed_get_parameter_questionaire_id) {
    $id = $form_state['build_info']['args'][0];
  } else {
    $id = !empty($form_state['values']['questionaire_id']) ? $form_state['values']['questionaire_id'] : '';
  }
  #dpm($id);
  $form['questionaire_selector'] = array(
    '#type' => 'fieldset',
    '#title' => t('Select 4D Questionaire'),
  );
  $form['questionaire_selector']['access_id'] = array(
    '#type' => 'hidden',
    '#value' => drupal_get_token(QUESTIONAIRE_4D_PREVIEW_AJAX_SECRET_VALUE),
  );
  $form['questionaire_selector']['questionaire_id'] = array(
    '#type' => 'textfield',
    '#title' => t('Questionaire Number'),
    '#default_value' => $id,
    '#element_validate' => array('element_validate_integer_positive'),
    '#size' => 15,
  );
  $form['questionaire_selector']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Preview 4D Questionaire'),
    '#ajax' => array(
      'callback' => 'questionaire_4d_selector_form_ajax_callback',
      'wrapper' => 'questionaire-preview',
      'method' => 'replace',
    ),
  );
  $form['preview-content-area'] = array(
    '#type' => 'fieldset',
  );
  $form['preview-content-area']['esci-questionaire'] = array(
    '#prefix' => '<div id="questionaire-preview">',
    '#suffix' => '</div>',
    '#type' => 'markup',
    '#markup' => '<h3>Your Questionaire Preview will appear here.</h3>',
  );

  // This says if we were given an remote 4D form id of say 23456, load it into the supplied FAPI
  // element.
  if ($form_passed_get_parameter_questionaire_id) {
    $remote_response = retrieve_questionaire_4d_response($id);
    if (strpos($remote_response->data, 'Error',0) === 0) {
      form_set_error('questionaire_selector', "<b>Remote 4D Error</b><br>" . $remote_response->data);
    }
    $form['preview-content-area']['esci-questionaire']['#markup'] = questionaire_4d_selector_build_esci_questionaire_preview($id, $remote_response->data);
  }

  $form['#attached']['css'] = array(
    drupal_get_path('module', 'questionaire_4d_preview') . '/assets/questionaire_4d_preview.css',
  );
  return $form;
}

/* Implements hook_menu() */
function questionaire_4d_preview_menu() {
  $items['admin/config/esci-online/questionaire-4d-preview'] = array(
    'title' => '4D Questionaire Preview',
    'description' => 'View a preview of a remote 4D questionare.',
    'page callback' => 'drupal_get_form',
    // I'm not sure we have to, but explicitly pass in the 4th
    // argument on the URL as the questionairre ID. This is added
    // to build_info of form automatically.
    'page arguments' => array('questionaire_4d_selector_form', 4),
    'type' => MENU_CALLBACK,
    'access arguments' => array('administer esci'),
  );
  return $items;
} 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.