Need to replace elements/values based on dropdown change event multiple times

I am building a form with form API in a custom module. Certain fields should be populated based on the selected value of a dropdown.

User will select the pre-entered profiles, based on which other fields should be populated.

I have used ajax callback on select box, it works fine for the first time. But not working on next time.

function multi_step_user_info_form($form, &$form_state) {
$form['user_data_form']['reference_number_ajax'] = array(
'#type' => 'select',
'#title' => 'Select a Patient', 
'#ajax' => array(
        'callback' => 'ref_number_dropdown_callback',
        'wrapper' => 'ref_number_list',
        'event' => 'change',
        'method' => 'replace',
        'effect' => 'fade',
        ),  
'#attributes' => array('class'=>array('dynamic-select')),
'#default_value' => isset($values['reference_number_ajax']) ? $values['reference_number_ajax'] : NULL,  
'#prefix'=>'<div class="col-md-12">', 
'#field_suffix'=>'</div>');  

$form['user_data_form']['patient_name'] = array('#type' => 'textfield',
'#title' => 'Patient Name','#value' => $patient_name, '#default_value' => isset($values['patient_name']) ? $values['patient_name'] : NULL, 
'#prefix'=>'<div id="ref_number_list"><div class="col-md-12">',
'#field_suffix'=>'' 
 ); 
return $form; 
} 

function ref_number_dropdown_callback($form, $form_state) {     
    $query = new EntityFieldQuery();
    $query->entityCondition('entity_type', 'node')
      ->entityCondition('bundle', 'query')
      ->propertyCondition('status', NODE_PUBLISHED)
      ->fieldCondition('field_reference_number', 'value', $form_state['values']['reference_number_ajax'], '=')
      ->range(0, 1);
    $result = $query->execute();
    $nid ='';
    if (isset($result['node'])) {
       $nid = $nid = current($result['node'])->nid;
       $node = node_load($nid);
    }
  //  $form_state['rebuild'] = TRUE;
  // THESE TWO VALUES SHOULD BE POPULATED ON AJAX CALLBACK //
    $form['user_data_form']['patient_name']['#value'] = $node->field_patientname[$node->language][0]['value'];
    $form['user_data_form']['age']['#value']          = $node->field_age[$node->language][0]['value'];
    $elements = array($form['user_data_form']['patient_name'],$form['user_data_form']['age']);
    return $elements;
  }

Comments

jaypan’s picture

Define 'works' and 'not working'.

Contact me to contract me for D7 -> D10/11 migrations.

lakshmananmariappan’s picture

Callback works for first time, but not on the second time.

When you select an option for the first time, after ajax loading the elements get replaced successfully. If you select another option, ajax loading happens but elements inside wrapper remains the same (which are supposed to change according to the currently selected option)

jaypan’s picture

It's probably because you are making changes to the form in the ajax callback. You cannot do this in Drupal, as the values do not get cached, and when the form is submitted (ajax or not), the submitted form does not match the cached form, which causes Drupal to fail. You should be making your changes in the form definition (you can determine whether or not it's been submitted by checking $form_state['values']), and only returning the relevant part of the form in the ajax callback.

Contact me to contract me for D7 -> D10/11 migrations.

lakshmananmariappan’s picture

Thanks Jaypan, It worked. I have used wrapper for every form element and assigned values through form itself (not on call back)

merrygoround’s picture

Hi lakshmananmariappan , I am now encounter the same problem.
What do you mean by assigned values through form itself but not on call back?
Do you mind share your code?

Thanks in advance.

nitin.k’s picture

Below code explains well..


function multi_step_user_info_form($form, &$form_state) {
  $form['user_data_form']['reference_number_ajax'] = array(
    '#type' => 'select',
    '#title' => 'Select a Patient',
    '#ajax' => array(
      'callback' => 'ref_number_dropdown_callback',
      'wrapper' => 'ref_number_list',
      'event' => 'change',
      'method' => 'replace',
      'effect' => 'fade',
    ),
    '#attributes' => array('class'=>array('dynamic-select')),
    '#default_value' => isset($values['reference_number_ajax']) ? $values['reference_number_ajax'] : NULL,  
    '#prefix' => '',
    '#field_suffix' => '',
  );

  $form['user_data_form']['patient_name'] = array('#type' => 'textfield',
    '#title' => 'Patient Name',
    '#value' => $patient_name,
    '#default_value' => isset($values['patient_name']) ? $values['patient_name'] : NULL,
    '#prefix'=>'',
    '#field_suffix'=>'',
  );
  return $form;
}

function ref_number_dropdown_callback($form, $form_state) {
    $query = new EntityFieldQuery();
    $query->entityCondition('entity_type', 'node')
      ->entityCondition('bundle', 'query')
      ->propertyCondition('status', NODE_PUBLISHED)
      ->fieldCondition('field_reference_number', 'value', $form_state['values']['reference_number_ajax'], '=')
      ->range(0, 1);
    $result = $query->execute();
    $nid ='';
    if (isset($result['node'])) {
       $nid = $nid = current($result['node'])->nid;
       $node = node_load($nid);
    }

    //  $form_state['rebuild'] = TRUE;
    // THESE TWO VALUES SHOULD BE POPULATED ON AJAX CALLBACK //


    /**
     * The mess is happening in the below code. I have provided detailed explanation.
     */
    /**
     * Point 1: You are trying to change the original form which scope is the local only.
     * point 2: If you want to achieve the same things then it can be achieved using hook_form_alter().
     * Point 3: The returning element is an array; you need to use render() function to see changes in the form of html().
     * Point 4: You need to define the wrapper in the form (ref_number_list), may be you have done.
     * Point 5: Use ajax.inc methods for changing DOM elements. It is the best killer.
     */

    $form['user_data_form']['patient_name']['#value'] = $node->field_patientname[$node->language][0]['value'];
    $form['user_data_form']['age']['#value']          = $node->field_age[$node->language][0]['value'];
    $elements = array($form['user_data_form']['patient_name'], $form['user_data_form']['age']);
    return $elements;
}


merrygoround’s picture

Thanks for your prompt reply.

I have just tried your codes but didn't see the changes in patient name field after changing the value of reference_number_ajax.

You mentioned in point 3 that The returning element is an array; you need to use render() function to see changes in the form of html().

May I know where should I put the render($form['user_data_form']['patient_name'])?
I am very new to Drupal and please execuse me if it's a stupid question.

Thanks again.

nitin.k’s picture

Returning form element from the callback will not be possible , as i mentioned.

render() should be used when you are returning an array like below..


$output['some_title'] = array(
 '#title' => 'Some title',
 '#type' => 'textfield',
 '#default_value' => 'some_value',
);
return render($output);

Dirst’s picture

I will try to explain. Do you see this form function? Everything you want to change on the form elements on the ajax callback should be within this function and not in ajax callback. Ajax callback need only to return parts of the form it is not for altering this elements.

function multi_step_user_info_form($form, &$form_state) {
  $form['user_data_form']['reference_number_ajax'] = array(
    '#type' => 'select',
    '#title' => 'Select a Patient',
    '#ajax' => array(
      'callback' => 'ref_number_dropdown_callback',
      'wrapper' => 'ref_number_list',  //THIS MEANS HTML ID OF THE ELEMENT WHERE ajax callback form element will be placed
      'event' => 'change',
      'method' => 'replace',
      'effect' => 'fade',
    ),
    '#attributes' => array('class'=>array('dynamic-select')),
    '#default_value' => isset($values['reference_number_ajax']) ? $values['reference_number_ajax'] : NULL,  
    '#prefix' => '',
    '#field_suffix' => '',
  );
  ////....
  $form['contain']['#type'] = 'container';
  $form['contain']['#prefix'] = '<div id="ref_number_list">';
  $form['contain']['#suffix'] = '</div">';
  /*ADD NEW ELEMENT AFTER AJAX CALL*/
  if($form_state['values']['reference_number_ajax'] == $some_value){
     $form['contain']['after-ajax-call']['#type'] = 'textfield';
  }
merrygoround’s picture

Thank you for your explanation.